按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
trashBins。addElement(
new Tbin(Glass。class));
// add one line here: (*3*)
trashBins。addElement(
new Tbin(Cardboard。class));
trashBins。sortBin(bin); // (*4*)
Enumeration e = trashBins。elements();
while(e。hasMoreElements()) {
Tbin b = (Tbin)e。nextElement();
Trash。sumValue(b);
}
Trash。sumValue(bin);
}
} ///:~
(1) TbinList容纳一系列 Tbin 句柄,所以在查找与我们传递给它的Trash 对象相符的情况时,sort()能通
过Tbin 继承。
(2) sortBin()允许我们将一个完整的 Tbin 传递进去,而且它会在 Tbin 里遍历,挑选出每种Trash,并将其
归类到特定的Tbin 中。请注意这些代码的通用性:新类型加入时,它本身不需要任何改动。只要新类型加入
(或发生其他事件)时大量代码都不需要变化,就表明我们设计的是一个容易扩展的系统。
(3) 现在可以体会添加新类型有多么容易了。为支持添加,只需要改动几行代码。如确实有必要,甚至可以
进一步地改进设计,使更多的代码都保持“固定”。
(4) 一个方法调用使bin 的内容归类到对应的、特定类型的垃圾筒里。
606
…………………………………………………………Page 608……………………………………………………………
16。6 多重派遣
上述设计方案肯定是令人满意的。系统内新类型的加入涉及添加或修改不同的类,但没有必要在系统内对代
码作大范围的改动。除此以外,RTTI 并不象它在 RecycleA。java 里那样被不当地使用。然而,我们仍然有可
能更深入一步,以最“纯”的角度来看待RTTI,考虑如何在垃圾分类系统中将它完全消灭。
为达到这个目标,首先必须认识到:对所有与不同类型有特殊关联的活动来说——比如侦测一种垃圾的具体
类型,并把它置入适当的垃圾筒里——这些活动都应当通过多形性以及动态绑定加以控制。
以前的例子都是先按类型排序,再对属于某种特殊类型的一系列元素进行操作。现在一旦需要操作特定的类
型,就请先停下来想一想。事实上,多形性(动态绑定的方法调用)整个的宗旨就是帮我们管理与不同类型
有特殊关联的信息。既然如此,为什么还要自己去检查类型呢?
答案在于大家或许不以为然的一个道理:Java 只执行单一派遣。也就是说,假如对多个类型未知的对象执行
某项操作,Java 只会为那些类型中的一种调用动态绑定机制。这当然不能解决问题,所以最后不得不人工判
断某些类型,才能有效地产生自己的动态绑定行为。
为解决这个缺陷,我们需要用到“多重派遣”机制,这意味着需要建立一个配置,使单一方法调用能产生多
个动态方法调用,从而在一次处理过程中正确判断出多种类型。为达到这个要求,需要对多个类型结构进行
操作:每一次派遣都需要一个类型结构。下面的例子将对两个结构进行操作:现有的 Trash 系列以及由垃圾
筒(Trash Bin)的类型构成的一个系列——不同的垃圾或废品将置入这些筒内。第二个分级结构并非绝对显
然的。在这种情况下,我们需要人为地创建它,以执行多重派遣(由于本例只涉及两次派遣,所以称为“双
重派遣”)。
16。6。1 实现双重派遣
记住多形性只能通过方法调用才能表现出来,所以假如想使双重派遣正确进行,必须执行两个方法调用:在
每种结构中都用一个来判断其中的类型。在Trash 结构中,将使用一个新的方法调用 addToBin(),它采用的
参数是由TypeBin 构成的一个数组。那个方法将在数组中遍历,尝试将自己加入适当的垃圾筒,这里正是双
重派遣发生的地方。
新建立的分级结构是TypeBin,其中包含了它自己的一个方法,名为add(),而且也应用了多形性。但要注意
一个新特点:add()已进行了“过载”处理,可接受不同的垃圾类型作为参数。因此,双重满足机制的一个关
键点是它也要涉及到过载。
程序的重新设计也带来了一个问题:现在的基础类 Trash 必须包含一个addToBin()方法。为解决这个问题,
一个最直接的办法是复制所有代码,并修改基础类。然而,假如没有对源码的控制权,那么还有另一个办法
可以考虑:将addToBin()方法置入一个接口内部,保持 Trash 不变,并继承新的、特殊的类型Aluminum ,
Paper,Glass 以及Cardboard。我们在这里准备采取后一个办法。
607
…………………………………………………………Page 609……………………………………………………………
这个设计方案中用到的大多数类都必须设为public (公用)属性,所以它们放置于自己的类内。下面列出接
口代码:
//: TypedBinMember。java
// An interface for adding the double dispatching
// method to the trash hierarchy without
// modifying the original hierarchy。
package c16。doubledispatch;
interface TypedBinMember {
// The new method:
boolean addToBin(TypedBin'' tb);
} ///:~
在Aluminum ,Paper,Glass 以及Cardboard 每个特定的子类型内,都会实现接口 TypeBinMember 的
addToBin()方法,但每种情况下使用的代码“似乎”都是完全一样的:
//: DDAluminum。java
// Aluminum for double dispatching
package c16。doubledispatch;
import c16。trash。*;
public class DDAluminum extends Aluminum
implements TypedBinMember {
public DDAluminum(double wt) { super(wt); }
public boolean addToBin(TypedBin'' tb) {
for(int i = 0; i 《 tb。length; i++)
if(tb'i'。add(this))
return true;
return false;
}
} ///:~
//: DDPaper。java
// Paper for double dispatching
package c16。doubledispatch;
import c16。trash。*;
public class DDPaper extends Paper
implements TypedBinMember {
public DDPaper(double wt) { super(wt); }
public boolean addToBin(TypedBin'' tb) {
for(int i = 0; i 《 tb。length; i++)
if(tb'i'。add(this))
return true;
return false;
}
} ///:~
//: DDGlass。java
// Glass for double dispatching
package c16。doubledispatch;
import c16。trash。*;
608
…………………………………………………………Page 610……………………………………………………………
public class DDGlass extends Glass
implements TypedBinMember {
public DDGlass(double wt) { super(wt); }
public boolean addToBin(TypedBin'' tb) {
for(int i = 0; i 《 tb。length; i++)
if(tb'i'。add(this))
return true;
return false;
}
} ///:~
//: DDCardboard。java
// Cardboard for double dispatching
package c16。doubledispatch;
import c16。trash。*;
public class DDCardboard extends Cardboard
implements Type