- 写在前面的话
- 引言
- 第 1 章 对象入门
- 第 2 章 一切都是对象
- 第 3 章 控制程序流程
- 第 4 章 初始化和清除
- 第 5 章 隐藏实施过程
- 第 6 章 类再生
- 第 7 章 多形性
- 第 8 章 对象的容纳
- 第 9 章 违例差错控制
- 第 10 章 Java IO 系统
- 第 11 章 运行期类型鉴定
- 第 12 章 传递和返回对象
- 第 十三 章 创建窗口和程序片
- 第 14 章 多线程
- 第 15 章 网络编程
- 第 16 章 设计范式
- 第 17 章 项目
- 附录 A 使用非 JAVA 代码
- 附录 B 对比 C++和 Java
- 附录 C Java 编程规则
- 附录 D 性能
- 附录 E 关于垃圾收集的一些话
- 附录 F 推荐读物
16.5 抽象的应用
走到这一步,接下来该考虑一下设计方案剩下的部分了——在哪里使用类?既然归类到垃圾箱的办法非常不雅且过于暴露,为什么不隔离那个过程,把它隐藏到一个类里呢?这就是著名的“如果必须做不雅的事情,至少应将其本地化到一个类里”规则。看起来就象下面这样:
现在,只要一种新类型的 Trash 加入方法,对 TrashSorter 对象的初始化就必须变动。可以想象,TrashSorter 类看起来应该象下面这个样子:
class TrashSorter extends Vector {
void sort(Trash t) { /* ... */ }
}
也就是说,TrashSorter 是由一系列句柄构成的 Vector(系列),而那些句柄指向的又是由 Trash 句柄构成的 Vector;利用 addElement(),可以安装新的 TrashSorter,如下所示:
TrashSorter ts = new TrashSorter();
ts.addElement(new Vector());
但是现在,sort() 却成为一个问题。用静态方式编码的方法如何应付一种新类型加入的事实呢?为解决这个问题,必须从 sort() 里将类型信息删除,使其需要做的所有事情就是调用一个通用方法,用它照料涉及类型处理的所有细节。这当然是对一个动态绑定方法进行描述的另一种方式。所以 sort() 会在序列中简单地遍历,并为每个 Vector 都调用一个动态绑定方法。由于这个方法的任务是收集它感兴趣的垃圾片,所以称之为 grab(Trash)。结构现在变成了下面这样:
其中,TrashSorter 需要调用每个 grab() 方法;然后根据当前 Vector 容纳的是什么类型,会获得一个不同的结果。也就是说,Vector 必须留意自己容纳的类型。解决这个问题的传统方法是创建一个基础“Trash bin”(垃圾筒)类,并为希望容纳的每个不同的类型都继承一个新的衍生类。若 Java 有一个参数化的类型机制,那就也许是最直接的方法。但对于这种机制应该为我们构建的各个类,我们不应该进行麻烦的手工编码,以后的“观察”方式提供了一种更好的编码方式。
OOP 设计一条基本的准则是“为状态的变化使用数据成员,为行为的变化使用多性形”。对于容纳 Paper(纸张)的 Vector,以及容纳 Glass(玻璃)的 Vector,大家最开始或许会认为分别用于它们的 grab() 方法肯定会产生不同的行为。但具体如何却完全取决于类型,而不是其他什么东西。可将其解释成一种不同的状态,而且由于 Java 有一个类可表示类型(Class),所以可用它判断特定的 Tbin 要容纳什么类型的 Trash。
用于 Tbin 的构建器要求我们为其传递自己选择的一个 Class。这样做可告诉 Vector 它希望容纳的是什么类型。随后,grab() 方法用 Class BinType 和 RTTI 来检查我们传递给它的 Trash 对象是否与它希望收集的类型相符。
下面列出完整的解决方案。设定为注释的编号(如*1*)便于大家对照程序后面列出的说明。
//: RecycleB.java // Adding more objects to the recycling problem package c16.recycleb; import c16.trash.*; import java.util.*; // A vector that admits only the right type: class Tbin extends Vector { Class binType; Tbin(Class binType) { this.binType = binType; } boolean grab(Trash t) { // Comparing class types: if(t.getClass().equals(binType)) { addElement(t); return true; // Object grabbed } return false; // Object not grabbed } } class TbinList extends Vector { //(*1*) boolean sort(Trash t) { Enumeration e = elements(); while(e.hasMoreElements()) { Tbin bin = (Tbin)e.nextElement(); if(bin.grab(t)) return true; } return false; // bin not found for t } void sortBin(Tbin bin) { // (*2*) Enumeration e = bin.elements(); while(e.hasMoreElements()) if(!sort((Trash)e.nextElement())) System.out.println("Bin not found"); } } public class RecycleB { static Tbin bin = new Tbin(Trash.class); public static void main(String[] args) { // Fill up the Trash bin: ParseTrash.fillBin("Trash.dat", bin); TbinList trashBins = new TbinList(); trashBins.addElement( new Tbin(Aluminum.class)); trashBins.addElement( new Tbin(Paper.class)); 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 的内容归类到对应的、特定类型的垃圾筒里。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论