Leemaasn(呆鸟一号)
谢谢你的祝愿,看到你,我很想改名作呆鸟二号俄,赫赫
谢谢你的祝愿,看到你,我很想改名作呆鸟二号俄,赫赫
解决方案 »
- 关于JLabel覆盖顺序的问题
- Class.forName(String name)方法到底如何使用????
- 用MyEclipse6连接mysql数据库时出现Communications link failure这个错误
- 以父类的变量访问子类的成员在程序上有什么好处?
- XML的编码方式问题!
- 怎么探测两点之间存在障碍物?
- 怎样产生一个不重复的随机整数?
- 关于jbuilder的问题?
- 如何实现一个线程组内多线程的非同不执行,即一个线程执行完毕后再执行下一个线程???
- Java对象与内存
- 怎么重命名文件 在线等待
- A[Y[(X[ch>>5]<<4)|((ch>>1)&0xF)]|(ch&0x1)]; 这是什么意思?
private B _b;这时最极端的情况就是直接把A对象本身传递给_b组件,这样前者能做的任何事后者肯定都可以做。譬如你原来的方法是:public class A{
public void doSomething() {
if(_b instanceof B1) {
invokeMethod1();
}
if(_b instanceof B2) {
invokeMethod2();
}
}那么你可以首先在B接口中声明一个doSomething()方法:public interface B {
public void doSomething(A a);在B1和B2中分别实现这个方法:public class B1 implements B {
public void doSomething(A a) {
a.invokeMethod1();
}public class B2 implements B {
public void doSomething(A a) {
a.invokeMethod2();最后把A里面的switch变成一个多态调用:public class A{
public void doSomething() {
_b.doSomething(this);
}这是一个基本的“用多态取代switch语句”的重构。每当你发现自己在做switch语句(尤其是针对类型的switch语句)时,你就应该首先考虑使用这个重构手法。真正需要instanceof的地方非常罕见,你必须证明自己这样做的合理性。我相信这样的多态调用绝对不会比一组针对类型的switch要来得慢。也可能你的doSomething操作根本不需要来自A的那些信息,那么就不必把A的对象传递给B了。第三,状态不好就不要写程序,早点休息。编程是脑力劳动,辛苦并不总是有回报的。
而我们的设计意图是,B各个子类只是封装他自己的行为属性,比如B2包含他自己的属性以及自身一些关联类,那么B2应该仅仅提供对这些属性和关联类的访问方法以及自身的一些处理方法,B2应该独立的设计自己的类层次,B2设计的时候并没有考虑到A对他的处理,在你所提供的方法里,B2的对A这种紧密的联系正是我们要避免的。其实在我们的项目里,分成了很多模块,模块有不同的人设计,模块之间的耦合也只是基于接口抽象层的耦合。而且,Class A所在的模块属于高层次的模块,B所在模块属于低层次的模块,用通俗的话来说“由我来调用你,而不是你来调用我“,采用这种方法将打破模块之间的松耦合
原贴内容:
不能回复,我只能在这里给你回复了:赫赫,我觉得你回答问题的本身就是违反了OOD原则。你的方法使用了一点技巧:就是通过参数传递Class A,使得能在Class B 里面调用A 的不同方法。这样的话,问题就来了,首先,B各个子类的得设计必须紧紧依赖的A的实现,A的各个方法必须根据B的不同子类来增加不同方法来共B调用。同时B里面又得紧紧依赖A所提供的方法。
而我们的设计意图是,B各个子类只是封装他自己的表现,比如B2包含他自己的属性以及自身一些关联类,那么B2应该仅仅提供对这些属性和关联类的访问方法以及自身的一些处理方法,B2应该独立的设计自己的类层次,B2设计的时候并没有考虑到A对他的处理,在你所提供的方法里,B2的对A这种紧密的联系正是我们要避免的。其实在我们的项目里,分成了很多模块,模块有不同的人设计,模块之间的耦合也只是基于接口抽象层的耦合。采用这种方法将打破模块之间的松耦合
4楼的方法不能说不好,但是比较消极,要知道在实际情况中是不可能让你改每个class的可能的解决方法比如用Integer 和 Float来示范:
import java.lang.reflect.*;
import java.util.*;class rtest {
public static void main(String[] args) throws Exception {
Object[] a = new Object[] {"35"};
System.out.println(new rtest(new Integer(1),a).invoke());
System.out.println(new rtest(new Float(1),a).invoke());
}
private Map m;
private Object o;
private Object[] args;
public rtest ( Object o, Object[] args ) {
m=new HashMap();
this.o =o;
this.args=args;
m.put("java.lang.Integer", new Object[] {"parseInt", new Class[] {java.lang.String.class}});
m.put("java.lang.Float", new Object[] {"parseFloat", new Class[] {java.lang.String.class}});
}
public Object invoke () throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Class cls = o.getClass();
String s = cls.getName();
if (m.keySet().contains(s)) {
Object[] item = (Object[])m.get(s);
String methodName = (String)item[0];
Class[] paramArray = (Class[])item[1];
Method meth = cls.getMethod (methodName,paramArray);
return meth.invoke(cls,args);
}
return null;
}
}
执行结果35
35.0时间仓促,做得比较不规范,catch exception等就不写了
要完善这个程序的话,最好是做一个 xml 的 dom configuration model
把class name, 方法,和参数 在程序执行的时候动态的读入加入到Map m中
再完善catch exception等,就可以比较好的解决问题
以后修改时只要修改xml配置文件即可
主程序根本不需要修改
也避免了庞大的switch statement
真的不错,看了你的想法我还以为这是我们项目讨论上的发言!!:)
不过,有些东西,自以为只能这样子却其实还有另外一种方法,如果我们没有发现,那才是我们工作最大失误!!!所以我来这里诚心听取大伙的意见。
真的这样吗?实践是另外一回事啊!或许,在j2ee里面,完全可以做出良好的设计,但是在一个包含更复杂逻辑的系统里面,未必这么简单拉!
但是想象一下,你这样写出来的程序其实是没有可维护性的
如果客户要修改一些小东西
那么可能就会存在对程序的大改,
只要在design是稍微多用一些力气完全可以做到一劳永逸
software design是一门系统的科学
不是所谓经验可以解决的关于 java reflection可参见 Java Reflection in Action 和 Professional Java XML 两本书
reflection对于我们不适合,其实我打心底里讨厌reflection机制,太动态的东西未必是好,一个简单的函数调用,非得写出那么一大堆东西来。看了你的程序,我觉得有必要再说清楚一点我的应用大致框架
我们的应用简化如下:
class A {
B[] bs;
public void do() {
for(int i=bs.length;i>=0;i--) {
b=bs[i];
if(b instanceof B2) {
View b_view =b.getView();
ViewData b_viewData=b_view.loadData();
//先对b_viewData做一些处理
//....
}
//常规处理
}}Class B {
..
public void doSomeThing();
}Class B1 exntends B {
....
public void doSonething() {
...
}
}
class B2 extends B {
View view;
....
public View getView() {
return this.view;
}
...
}
reflection对于我们不适合,其实我打心底里讨厌reflection机制,太动态的东西未必是好,一个简单的函数调用,非得写出那么一大堆东西来。看了你的程序,我觉得有必要再说清楚一点我的应用大致框架那俺也没有什么话好说了
当你有b1....b200甚至b2000 extends b时
就知道reflection的好处了
小程序嘛
随便做做就可以了
说一下我的看法:(注 - 不知道楼主项目的具体情况,只说说大概)这个问题比较抽象,也比较形而上。在面向对象的设计中,多态性是一个很重要的设计原则和目标,很多时候我们都应
该考虑如何把多态性用好,这一点上我赞成扇兄的说法。当你发现你经常使用
instanceof作类型鉴别,那也许真的需要要考虑这样的设计是否合理。楼主的问题,我想,问题的关键在以何种途径实现RTTI(运行期类型判定)更合理。
多态是一种方式,强制类型转换是一种方式,通过instanceof判断是一种方式,通
过Class.isInstance方法也是一种方式。要根据实际情况选择采用哪一种方式,更
多的时候,我们也许应该选择上述方式的组合。并不是所有时候应该用多态,因为
在某些特定的情况下,多态实现起来也许会有过大的开销,牵扯更大范围的改动。楼主是不是可以考虑一个折衷的方案:在子组件的级别做好接口和类的清晰层次结
构,在这个层次好好实现抽象和多态,到高级别的组件中,如果需要对传入的子组
件进行操作,可以利用instanceof判断一个大致的类别(当然也可以是一个接口),
然后对该类别执行相对简单的多态调用,这样会避免过多的instanceof出现,同时
也可以很高效。一点拙见,如有不对或者不妥之处,请指正。希望对楼主有帮助。
{
visit(B b)
{
}; visit(B1 b)
{
}; visit(B2 b)
{
View b_view =b.getView();
ViewData b_viewData=b_view.loadData();
//先对b_viewData做一些处理
//....
} }; dosomething
{
...
b.accept(this);
...
}
}class B
{
accept(Visitor v)
{
v.visit(this);
}
}
不要乱用设计模式啊,dosomething里直接调用visit(b)就行了,楼主并不想成套改变A对B族的操作。
你这叫为反射而反射。Number类型(Integer和Float共有的基类)都有接收String参数的constructor,你干吗不直接调用constructor?
俺只不过举一个例子而已
随手写着玩玩而已
俺只不过举一个例子而已
随手写着玩玩而已另外 如果俺要加一个ArrayList 和 add 怎么办?也调constructor?
import java.util.*;class rtest {
public static void main(String[] args) throws Exception {
Object[] a = new Object[] {"35"};
System.out.println(new rtest(new ArrayList(),a).invoke());
System.out.println(new rtest(new HashSet(),a).invoke());
}
private Map m;
private Object o;
private Object[] args;
public rtest ( Object o, Object[] args ) {
m=new HashMap();
this.o =o;
this.args=args;
m.put("java.util.ArrayList", new Object[] {"add", new Class[] {java.lang.Object.class}});
m.put("java.util.HashSet", new Object[] {"contains", new Class[] {java.lang.Object.class}});
}
public Object invoke () throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Class cls = o.getClass();
String s = cls.getName();
if (m.keySet().contains(s)) {
Object[] item = (Object[])m.get(s);
String methodName = (String)item[0];
Class[] paramArray = (Class[])item[1];
Method meth = cls.getMethod (methodName,paramArray);
return meth.invoke(o,args);
}
return null;
}
{
public void visit(B b);
public void visit(B1 b);
public void visit(B2 b);
}class B
{
public void accept(BVisitor v){
v.visit(this);
};
}class B1 extends B
{
public void accept(BVisitor v){
v.visit(this);
};
}class B2 extends B
{
public void accept(BVisitor v){
v.visit(this);
};
}public class A implements BVisitor
{
public void visit(B b){
System.out.println("visit B");
};
public void visit(B1 b){
System.out.println("visit B1");
};
public void visit(B2 b){
System.out.println("visit B2");
};
public void doSomething(B b)
{
b.accept(this);
}
public static void main(String[] args){
B b = new B();
B1 b1 = new B1();
B2 b2 = new B2();
test t = new test();
t.doSomething(b);
t.doSomething(b1);
t.doSomething(b2);
}
}
这个例子就更是瞎搞。“如果传入一个ArrayList,则做add方法;如果传入一个HashSet,则做contains方法”,别的我就不问了,只请教一个问题:你打算给这个功能叫个什么名字?我看只有叫它“魔术盒”,除了魔术师本人,谁都别想知道下次变出来的是鸽子还是兔子。这个例子证明了“在必须使用反射的时候,你就必须使用反射”,除此之外我看不出还有什么意义。
t.doSomething(b);
t.doSomething(b1);
t.doSomething(b2);为
A a = new A();
a.doSomething(b);
a.doSomething(b1);
a.doSomething(b2);
我原来是用test 作A类的
如果按照你的例子,那么B就不应该是B1、B2的超类,而应该是并列的几个类。既然client不是通过B这个接口、而是直接知道B1和B2,那还要这个接口来有什么用?你的例子也证明这个对象体系的设计确实有问题。
所以我说楼主的对象体系本身就有问题呢。对于一个简单的“接口-实现”两层体系,如果使用者还必须知道实现类的存在,这个接口就没有存在的必要,实际不过是一群多少有些相似的具体类型被强行放在一起而已。
1.有一个主题主件类A;
2.有很多子组件B1,B2,B3...它们都是主题主件A的子类。
3.主题组件有一些方法,它们的参数是子组件的共同接口或超类(此处,很可能是A)。变量传入以后,需要判断这个类到底是哪个子组件的实例,并作出相应的动作。所以楼主采用的方法是使用instanceof操作符配合switch语句。针对上述意思,我谈谈解决方法。
一种方法是,放弃子组件的共同接口作为参数,使用自组件本身作为参数。既:doSomething(A argument)改成doSomething(Bx argument)。doSomething被重载,有多少个子组件,就要被重载多少次。优点仅仅是避免了swithc和instanceof,缺点是缺乏可扩展性。有了新的子类,就要加一个新的重载方法。
第二种方法是,把原本判断这个类的实例以后要做的“相应动作”抽象成一个方法,置入子组件的共同父类中;然后每一个自构件按照需要复写这个方法。doSomething(A argument)内部就调用argument对象的这个方法。由于方法的后期内联,不必判断A到底是谁的实例,A的方法总是执行相应子类复写后的方法。不过,我总觉得楼主的设计有点不合理。如果我没有理解错的话,A和它的子类B1,B2...不仅仅有继承关系,还有复合关系。如此双重的耦合关系总让我觉得别扭。
>>B类型体系的设计就根本上违反了OO原则。实现类不应该提供超出接口范围的方法(我忘记这条原则叫什么名字了)。就拿你的例子来说,既然B接口上只有doSomething()方法,那么对于client(也就是A)来说,B的任何实现类都只有这一个方法,其余的方法(像getView()之类的)只是它自己使用.
这个,是因为我没有说清楚:我得类图如下
|A:interface|----->|B:interface|-------->|C:interface| (抽象层的耦合)interface A {
public void getSize(B[] b);
}
interface B {
public void dosomething();
public C getData();
}
interface C {
public int getLength();
public int getWidth();
public int getSize();
......
}
class A1 implements A {
B b;
public int getSize() {
C c=b.getData();
if(c instanceof C***) {
return c.getLengh+78;
}
//不是C***,则进行一些一般化计算!
} 我想强调的我的观点:
在什么情况下,你不得不用instanceof呢?首先,在高层次组件与低层次组件间的基于抽象层的关联(依赖)将必定导致instanceof的使用,为什么呢?因为抽象层的操作 返回的仅仅是cast为抽象层类的引用,而且这些诸如getData(),getDocument()无参数的函数调用更是要命。你根本没办法进行参数RTTI判定,但是这种诸如get***()无参数的函数切是我们常用的!
当你对这些已经得到的抽象层的引用而进行进一步得操作时,你不得不用INSTANCEOF进行判断了,真的很难避免!
另外,我觉得我们的设计应该没有违背大的ood原则!我所举的例子只是写的仓促,导致一些误会罢了!
interface A {
public void getSize();
publc B getView();
}
class A1 implements A {
B b;
public int getSize() {
C c=b.getData();
if(c instanceof C***) {
return c.getLengh+78;
}
return c.getLengh+78;
}
//不是C***,则进行一些一般化计算!
public B getView() {
return this.b;
}
}
>>第二个疑问:如果A首先通过B获得C,然后计算size,那还要B来干什么?即便C不能提供计>>算size的逻辑(可能是因为无法获得足够的信息),这件事情也应该由B来做。否则,就不>>应该让B保管C的对象,因为它没有尽到保管员的责任。
length size只是个比喻而已!可能不是很准确!
结合我的需求来看可能更好一点(需求我发给你留言里),这里,B可以理解为对model (class C) 的controller,具体为一个可视化操作组件,他关联着model C。, A最后根据所有B拥有的model生成xml文件,这里A只是简单的取得B关联的model,在进行处理。
InstanceOf 的使用是由于体系的设计有了问题。
记得<<Bitter Java>>上对此有具体的分析。
基本上可以用Interface, 以及Abstract Class解决。
99.9%的情况下可以用interface和abstract class实现
我也同意你的观点,visitor模式便是解决instanceof的最好办法,但是visitor模式的引入破坏了组件之间的独立性。
解决不用instanceof不一定带来好处!
:switch + instanceof,个人不太喜欢,主要是感觉扩展性不好,而且也不喜欢那种编码风格(个人比较喜欢用很少的一致的代码):bImp.doSomeThing( aInstance) 有的时候自己也这么用,看了好些写开源的那些高人们也那么用,但是始终疑惑的是这样A,B之间的耦合岂不又变紧?当然可以用bridge解藕,但是感觉这个和oo没有任何关系--为了解藕而增加的类和行为.:reflect 反正我不喜欢这么用,除了众所周知的效率问题,方法签名根本不能带给使用者足够的信息,而且感觉很象c++代码.始终有个疑惑,就是当初学习Adapt模式的时候,为什么一个设计刚开始的时候就想到重构.....怎么做到少用?......又是一个经验的问题
很粗糙地浏览了一下楼上各位飞鸟们的说法,
结合接口、抽象、具体类、反射、工厂说说我的想法,
如果我说的楼上各位已经说到了,
先不要说我抄袭,可能是我没有看仔细而失察。
如果楼主有比我更好的观点,也请不吝赐教。
不过,这个帖子太沉重了,压得我替楼主喘不过气来。嘿嘿。
********************************************
这个帖子谈到了多态,按照我的想法+做法,
我一般会采取根据需求整理出系统概要设计,然后根据设计,抽象出统一接口!
根据楼主的Example和解说,我进行了大胆妄为地臆测(臆测过头不要丢我XXX):
先附楼主的Example,免得各位鼠标上下翻滚,嘻。
interface A {
public void getSize();
publc B getView();
}
class A1 implements A {
B b;
public int getSize() {
C c=b.getData();
if(c instanceof C***) {
return c.getLengh+78;
}
return c.getLengh+78;
}
//不是C***,则进行一些一般化计算!
public B getView() {
return this.b;
}
}
下面是我的臆测:
从这里
C c=b.getData();
if(c instanceof C***) {
我臆测楼主所说的从
b.getData();
得到的Object是一个实现了C Interface的多种类型的Object。
如果该Object是C***,则调用c.getLengh方法,
===========================
在这里,我有个想法,楼主为何不在这里,先定义一个抽象类(AbstractCImpl),
该抽象类可以实现了部分C接口!
然后在AbstractCImpl里定一个抽象的公共Method(AbstractGetLength)?
然后在具体的、你原来的、每个实现了C Interface的C***类里,均继承于AbstractCImpl
它们都实现自己的AbstractGetLength方法,
如:
C***1.AbstractGetLength(
return value1;
);
C***2.AbstractGetLength(
return value2;
);
C***3.AbstractGetLength(
return ThisMethodNotImplementionException;
);然后,在具体的
C c=b.getData();
你可以返回C,也可以返回AbstractCImpl,可以考虑,似乎不推荐!
然后调用
AbstractCImpl.AbstractGetLength();
这样,是否可以避免楼主javer6 (孤舟万里)的设计里的instanceof了呢?其实我一般的做法和我上面说的参考解决方法都是差不多的。
不过,我更多地用到了Factory、Object Pool和Reflection,
如果,注意,这里说的是如果(If)!
如果我能预测到某个类或者说是对象将会被多次Create和Invoke,
我会考虑采用Pool和Factory,先预创建一些以备用,等用到的时候,直接取不是很好吗?
性能低吗?似乎不吧?!什么时候用到Reflection呢?
在这里:
C***1,C***2,C***3
你是在工厂里指定C***X来创建呢,还是系统通过配置文件,采用Reflect来创建呢?
如果是我,我当然用后者了,嘻。还有个好处,如果以后我发现某个类需要更新,通过配置文件+Reflect不是更好吗?
熟悉Struts(这里是顺手举的,Reflect用得好的不只Struts,看看Web.xml中关于Servlet的定义就知道了)应该更容易理解。==========================
不过,我水平也菜,楼主举的例子,我真的不是很清晰+明白楼主想要表达的意图。
我只是泛泛而谈自己的想法,如有不合理的地方(肯定有的,我不了解的楼主的需求+设计嘛),
楼主可要指出哦,要不然,我可真是“帖子夜未眠”了。哈。
====================一些相关背景,我在这下面两个帖子有给出介绍。大家如果有兴趣,可以去看看,
不过,讨论就在这边好了,不要两边跑,累,嘻嘻。
http://expert.csdn.net/Expert/TopicView1.asp?id=2692504
http://expert.csdn.net/Expert/TopicView1.asp?id=2887237==============================
另外,
Schlemiel(维特根斯坦的扇子)大鸟说的:
***********
to 楼主:
刚才认真看了一下你给的代码。B类型体系的设计就根本上违反了OO原则。实现类不应该提供超出接口范围的方法(我忘记这条原则叫什么名字了)。就拿你的例子来说,既然B接口上只有doSomething()方法,那么对于client(也就是A)来说,B的任何实现类都只有这一个方法,其余的方法(像getView()之类的)只是它自己使用,client根本不知道这些方法的存在。你想想看,像你上面的代码,client都知道B2这个具体类型的存在了,那么B2类型就是不可替换的,你不可能将这个类型删掉,A这个client要依赖于B2这个具体类型,这叫什么面向对象设计?OOD最根本的思想就是“针对接口编程”,你连这个根本都破坏了,还谈什么OOD的局限?
如果整个问题确实就像你说的这样,那么你把那块特定于B2的代码放到B2的doSomething()方法里面不就结了吗?为什么还说“做不到”?
这个例子我同样看不太明白。首先从B对象获得一个C对象,然后根据C对象来计算size?这违反了Demeter法则:每个对象应该只和最亲密的对象接触。每当出现这种情况时,肯定是对象的职责没有划分清楚,有些对象没有承担应有的责任。
第一个疑问:为什么要把“根据C对象的某些属性计算size”的工作放在A对象中完成?既然length、size这些属性都在C那里,C当然应该在getSize()里面封装计算size的逻辑,不然如果你在另一个地方需要size,难道再把这段逻辑重新写一遍?你可能会说:计算size有不同的逻辑。那么好,你应该把这些逻辑封装成Strategy模式。
第二个疑问:如果A首先通过B获得C,然后计算size,那还要B来干什么?即便C不能提供计算size的逻辑(可能是因为无法获得足够的信息),这件事情也应该由B来做。否则,就不应该让B保管C的对象,因为它没有尽到保管员的责任。
*****************
楼主或许需要再重新回味一下。
==================
Factory+Object Pool+Reflection用得好,效率+性能也不会很低吧?
感觉很象c++代码.
????
怎么个像法?**************
始终有个疑惑,就是当初学习Adapt模式的时候,为什么一个设计刚开始的时候就想到重构.....怎么做到少用?......又是一个经验的问题
==========
重构确实不容易!!!
instanceof有时候是不可避免的,但是好的OOD是应该尽量避免instanceof
99.9%的情况下可以用interface和abstract class实现
======================
强烈同意!!!
我也喜欢用
interface和abstract class
不过,interface和abstract class用得多了,会给人一种神秘迷宫感(当别人看你的代码的时候,我是从看HttpUnit和Hibernate的源码得来的呆鸟之烦恼)!!!to:楼主javer6 (孤舟万里)
你说的,
“A最后根据所有B拥有的model生成xml文件”,个人认为,这个生成的实现,应该放到
CXXX里,A只是负责调用而已,
CXXX不支持可以抛出ThisMethodNotImplementionException!************************
周末出去玩,没想到一回来,此帖将过“知天命”了,
赶紧插嘴,免得“古稀之年”了,打趣!
楼主活蹦乱跳没问题了吧?
**************************
回复人: ldianfeng(呆鸟三号) ( ) 信誉:105 2004-03-27 19:05:00 得分:0
我是(呆鸟三号)
晕。
还有这种事?放着
系统鸟:Schlemiel(维特根斯坦的扇子)、
骨灰鸟:sean_gao(大胃) 、
设计鸟:javer6 (孤舟万里)、
啄木鸟:zcjl、
狂鸟:alienbat(亡灵法师)、 Sheepy(-[J.2.E.E]-)、
土豆鸟:Totodo(土豆仙)、
大鸟们不学,
却来仿呆鸟?我可是要收版权的哦。哈哈。。