Java编程思想第4版[中文版](PDF格式)-第158部分
按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
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
c16。TrashVisitor。VGlass:80
c16。TrashVisitor。VAluminum:81
c16。TrashVisitor。VCardboard:12
c16。TrashVisitor。VGlass:12
615
…………………………………………………………Page 617……………………………………………………………
c16。TrashVisitor。VGlass:54
c16。TrashVisitor。VAluminum:36
c16。TrashVisitor。VAluminum:93
c16。TrashVisitor。VGlass:93
c16。TrashVisitor。VPaper:80
c16。TrashVisitor。VGlass:36
c16。TrashVisitor。VGlass:12
c16。TrashVisitor。VGlass:60
c16。TrashVisitor。VPaper:66
c16。TrashVisitor。VAluminum:36
c16。TrashVisitor。VCardboard:22
程序剩余的部分将创建特定的 Visitor 类型,并通过一个 Trash 对象列表发送它们:
//: TrashVisitor。java
// The 〃visitor〃 pattern
package c16。trashvisitor;
import c16。trash。*;
import java。util。*;
// Specific group of algorithms packaged
// in each implementation of Visitor:
class PriceVisitor implements Visitor {
private double alSum; // Aluminum
private double pSum; // Paper
private double gSum; // Glass
private double cSum; // Cardboard
public void visit(VAluminum al) {
double v = al。weight() * al。value();
System。out。println(
〃value of Aluminum= 〃 + v);
alSum += v;
}
public void visit(VPaper p) {
double v = p。weight() * p。value();
System。out。println(
〃value of Paper= 〃 + v);
pSum += v;
}
public void visit(VGlass g) {
double v = g。weight() * g。value();
System。out。println(
〃value of Glass= 〃 + v);
gSum += v;
}
public void visit(VCardboard c) {
double v = c。weight() * c。value() ;
System。out。println(
〃value of Cardboard = 〃 + v);
cSum += v;
}
void total() {
616
…………………………………………………………Page 618……………………………………………………………
System。out。println(
〃Total Aluminum: 〃 + alSum + 〃n〃 +
〃Total Paper: 〃 + pSum + 〃n〃 +
〃Total Glass: 〃 + gSum + 〃n〃 +
〃Total Cardboard: 〃 + cSum);
}
}
class WeightVisitor implements Visitor {
private double alSum; // Aluminum
private double pSum; // Paper
private double gSum; // Glass
private double cSum; // Cardboard
public void visit(VAluminum al) {
alSum += al。weight();
System。out。println(〃weight of Aluminum = 〃
+ al。weight());
}
public void visit(VPaper p) {
pSum += p。weight();
System。out。println(〃weight of Paper = 〃
+ p。weight());
}
public void visit(VGlass g) {
gSum += g。weight();
System。out。println(〃weight of Glass = 〃
+ g。weight());
}
public void visit(VCardboard c) {
cSum += c。weight();
System。out。println(〃weight of Cardboard = 〃
+ c。weight());
}
void total() {
System。out。println(〃Total weight Aluminum:〃
+ alSum);
System。out。println(〃Total weight Paper:〃
+ pSum);
System。out。println(〃Total weight Glass:〃
+ gSum);
System。out。println(〃Total weight Cardboard:〃
+ cSum);
}
}
public class TrashVisitor {
public static void main(String'' args) {
Vector bin = new Vector();
// ParseTrash still works; without changes:
ParseTrash。fillBin(〃VTrash。dat〃; bin);
// You could even iterate through
// a list of visitors!
617
…………………………………………………………Page 619……………………………………………………………
PriceVisitor pv = new PriceVisitor();
WeightVisitor wv = new WeightVisitor();
Enumeration it = bin。elements();
while(it。hasMoreElements()) {
Visitable v = (Visitable)it。nextElement();
v。accept(pv);
v。accept(wv);
}
pv。total();
wv。total();
}
} ///:~
注意main()的形状已再次发生了变化。现在只有一个垃圾(Trash)筒。两个Visitor 对象被接收到序列中
的每个元素内,它们会完成自己份内的工作。Visitor 跟踪它们自己的内部数据,计算出总重和价格。
最好,将东西从序列中取出的时候,除了不可避免地向Trash 造型以外,再没有运行期的类型验证。若在
Java 里实现了参数化类型,甚至那个造型操作也可以避免。
对比之前介绍过的双重派遣方案,区分这两种方案的一个办法是:在双重派遣方案中,每个子类创建时只会
过载其中的一个过载方法,即 add()。而在这里,每个过载的visit()方法都必须在 Visitor 的每个子类中进
行过载。
1。 更多的结合?
这里还有其他许多代码,Trash 结构和 Visitor 结构之间存在着明显的“结合”(Coupling )关系。然而,
在它们所代表的类集内部,也存在着高度的凝聚力:都只做一件事情(Trash 描述垃圾或废品,而Visitor
描述对垃圾采取什么行动)。作为一套优秀的设计方案,这无疑是个良好的开端。当然就目前的情况来说,
只有在我们添加新的Visitor 类型时才能体会到它的好处。但在添加新类型的Trash 时,它却显得有些碍手
碍脚。
类与类之间低度的结合与类内高度的凝聚无疑是一个重要的设计目标。但只要稍不留神,就可能妨碍我们得
到一个本该更出色的设计。从表面看,有些类不可避免地相互间存在着一些“亲密”关系。这种关系通常是
成对发生的,可以叫作“对联”(Couplet)——比如集合和继承器(Enumeration)。前面的Trash
Visitor 对似乎也是这样的一种“对联”。
16。8 RTTI 真的有害吗
本章的各种设计方案都在努力避免使用RTTI,这或许会给大家留下“RTTI 有害”的印象(还记得可怜的
goto 吗,由于给人印象不佳,根本就没有放到Java 里来)。但实际情况并非绝对如此。正确地说,应该是
RTTI 使用不当才“有害”。我们之所以想避免 RTTI 的使用,是由于它的错误运用会造成扩展性受到损害。
而我们事前提出的目标就是能向系统自由加入新类型,同时保证对周围的代码造成尽可能小的影响。由于
RTTI 常被滥用(让它查找系统中的每一种类型),会造成代码的扩展能力大打折扣——添加一种新类型时,
必须找出使用了RTTI 的所有代码。即使仅遗漏了其中的一个,也不能从编译器那里得到任何帮助。
然而,RTTI 本身并不会自动产生非扩展性的代码。让我们再来看一看前面提到的垃圾回收例子。这一次准备
引入一种新工具,我把它叫作TypeMap。其中包含了一个Hashtable (散列表),其中容纳了多个Vector,
但接口非常简单:可以添加(add())一个新对象,可以获得(get())一个Vector,其中包含了属于某种特
定类型的所有对象。对于这个包含的散列表,它的关键在于对应的Vector 里的类型。这种设计方案的优点
(根据Larry O'Brien 的建议)是在遇到一种新类型的时候,TypeMap 会动态加入一种新类型。所以不管什
么时候,只要将一种新类型加入系统(即使在运行期间添加),它也会正确无误地得以接受。
我们的例子同样建立在 c16。Trash 这个“包”(Package)内的Trash 类型结构的基础上(而且那儿使用的
Trash。dat 文件可以照搬到这里来)。
//: DynaTrash。java
// Using a Hashtable of Vectors and RTTI
// to automatically sort trash into
// vectors。 This solution; desp ite the
618
…………………………………………………………Page 620……………………………………………………………
// use of RTTI; is extensible。
package c16。dynatrash;
import c16。trash。*;
import java。util。*;
// Generic TypeMap works in any situation:
class TypeMap {
private Hashtable t = new Hashtable();
public void add(Object o) {
Class type = o。getClass();
if(t。containsKey(type))
((Vector)t。get(type))。addElement(o);
else {
Vector v = new Vector();
v。addElement(o);
t。put(type;v);
}
}
public Vector get(Class type) {
return (Vector)t。get(type);
}
public Enumeration keys() { return t。keys(); }
// Returns handle to adapter class to allow
// callbacks from ParseTrash。fillBin():
public Fillable filler() {
// Anonymous inner class:
return new Fillable() {
public void addTrash(Trash t