按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
// 。。。 and for the master bin
Trash。sumValue(bin);
}
} ///:~
其中,TrashBinSet 封装了各种不同类型的 TypeBin,同时还有 sortIntoBins()方法。所有双重派遣事件都
会在那个方法里发生。可以看到,一旦设置好结构,再归类成各种TypeBin 的工作就变得十分简单了。除此
以外,两个动态方法调用的效率可能也比其他排序方法高一些。
注意这个系统的方便性主要体现在 main()中,同时还要注意到任何特定的类型信息在main()中都是完全独立
的。只与Trash 基础类接口通信的其他所有方法都不会受到Trash 类中发生的改变的干扰。
添加新类型需要作出的改动是完全孤立的:我们随同 addToBin()方法继承Trash 的新类型,然后继承一个新
的TypeBin (这实际只是一个副本,可以简单地编辑),最后将一种新类型加入TrashBinSet 的集合初化化
过程。
16。7 访问器范式
接下来,让我们思考如何将具有完全不同目标的一个设计范式应用到垃圾归类系统。
对这个范式,我们不再关心在系统中加入新型 Trash 时的优化。事实上,这个范式使新型Trash 的添加显得
更加复杂。假定我们有一个基本类结构,它是固定不变的;它或许来自另一个开发者或公司,我们无权对那
个结构进行任何修改。然而,我们又希望在那个结构里加入新的多形性方法。这意味着我们一般必须在基础
类的接口里添加某些东西。因此,我们目前面临的困境是一方面需要向基础类添加方法,另一方面又不能改
动基础类。怎样解决这个问题呢?
“访问器”(Visitor)范式使我们能扩展基本类型的接口,方法是创建类型为Visitor 的一个独立的类结
构,对以后需对基本类型采取的操作进行虚拟。基本类型的任务就是简单地“接收”访问器,然后调用访问
器的动态绑定方法。看起来就象下面这样:
612
…………………………………………………………Page 614……………………………………………………………
现在,假如 v 是一个指向 Aluminum (铝制品)的Visitable 句柄,那么下述代码:
PriceVisitor pv = new PriceVisitor();
v。accept(pv);
会造成两个多形性方法调用:第一个会选择accept()的Aluminum 版本;第二个则在 accept()里——用基础
类Visitor 句柄v 动态调用 visit()的特定版本时。
这种配置意味着可采取 Visitor 的新子类的形式将新的功能添加到系统里,没必要接触Trash 结构。这就是
“访问器”范式最主要的优点:可为一个类结构添加新的多形性功能,同时不必改动结构——只要安装好了
accept()方法。注意这个优点在这儿是有用的,但并不一定是我们在任何情况下的首选方案。所以在最开始
的时候,就要判断这到底是不是自己需要的方案。
现在注意一件没有做成的事情:访问器方案防止了从主控 Trash 序列向单独类型序列的归类。所以我们可将
所有东西都留在单主控序列中,只需用适当的访问器通过那个序列传递,即可达到希望的目标。尽管这似乎
并非访问器范式的本意,但确实让我们达到了很希望达到的一个目标(避免使用RTTI )。
访问器范式中的双生派遣负责同时判断Trash 以及Visitor 的类型。在下面的例子中,大家可看到Visitor
的两种实现方式:PriceVisitor 用于判断总计及价格,而WeightVisitor 用于跟踪重量。
可以看到,所有这些都是用回收程序一个新的、改进过的版本实现的。而且和DoubleDispatch。java 一样,
Trash 类被保持孤立,并创建一个新接口来添加 accept()方法:
613
…………………………………………………………Page 615……………………………………………………………
//: Visitable。java
// An interface to add visitor functionality to
// the Trash hierarchy without modifying the
// base class。
package c16。trashvisitor;
import c16。trash。*;
interface Visitable {
// The new method:
void accept(Visitor v);
} ///:~
Aluminum ,Paper,Glass 以及Cardboard 的子类型实现了accept()方法:
//: VAluminum。java
// Aluminum for the visitor pattern
package c16。trashvisitor;
import c16。trash。*;
public class VAluminum extends Aluminum
implements Visitable {
public VAluminum(double wt) { super(wt); }
public void accept(Visitor v) {
v。visit(this);
}
} ///:~
//: VPaper。java
// Paper for the visitor pattern
package c16。trashvisitor;
import c16。trash。*;
public class VPaper extends Paper
implements Visitable {
public VPaper(double wt) { super(wt); }
public void accept(Visitor v) {
v。visit(this);
}
} ///:~
//: VGlass。java
// Glass for the visitor pattern
package c16。trashvisitor;
import c16。trash。*;
public class VGlass extends Glass
implements Visitable {
public VGlass(double wt) { super(wt); }
public void accept(Visitor v) {
v。visit(this);
}
} ///:~
//: VCardboard。java
614
…………………………………………………………Page 616……………………………………………………………
// Cardboard for the visitor pattern
package c16。trashvisitor;
import c16。trash。*;
public class VCardboard extends Cardboard
implements Visitable {
public VCardboard(double wt) { super(wt); }
public void accept(Visitor v) {
v。visit(this);
}
} ///:~
由于Visitor 基础类没有什么需要实在的东西,可将其创建成一个接口:
//: Visitor。java
// The base interface for visitors
package c16。trashvisitor;
import c16。trash。*;
interface Visitor {
void visit(VAluminum a);
void visit(VPaper p);
void visit(VGlass g);
void visit(VCardboard c);
} ///:~
Once again custom Trash types have been created in a different subdirectory。 The new Trash data
file is VTrash。dat and looks like this:
c16。TrashVisitor。VGlass:54
c16。TrashVisitor。VPaper:22
c16。TrashVisitor。VPaper:11
c16。TrashVisitor。VGlass:17
c16。TrashVisitor。VAluminum:89
c16。TrashVisitor。VPaper:88
c16。TrashVisitor。VAluminum:76
c16。TrashVisitor。VCardboard:96
c16。TrashVisitor。VAluminum:25
c16。TrashVisitor。VAluminum:34
c16。TrashVisitor。VGlass:11
c16。TrashVisitor。VGlass:68
c16。TrashVisitor。VGlass:43
c16。TrashVisitor。VAluminum:27
c16。TrashVisitor。VCardboard:44
c16。TrashVisitor。VAluminum:18
c16。TrashVisitor。VPaper:91
c16。TrashVisitor。VGlass:63
c16。TrashVisitor。VGlass:50
c