- 写在前面的话
- 引言
- 第 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.4.1 制作更多的对象
这样便引出了面向对象程序设计时一条常规的准则,我最早是在 Grady Booch 那里听说的:“若设计过于复杂,就制作更多的对象”。尽管听起来有些暧昧,且简单得可笑,但这确实是我知道的最有用一条准则(大家以后会注意到“制作更多的对象”经常等同于“添加另一个层次的迂回”)。一般情况下,如果发现一个地方充斥着大量繁复的代码,就需要考虑什么类能使它显得清爽一些。用这种方式整理系统,往往会得到一个更好的结构,也使程序更加灵活。
首先考虑 Trash 对象首次创建的地方,这是 main() 里的一个 switch 语句:
for(int i = 0; i < 30; i++) switch((int)(Math.random() * 3)) { case 0 : bin.addElement(new Aluminum(Math.random() * 100)); break; case 1 : bin.addElement(new Paper(Math.random() * 100)); break; case 2 : bin.addElement(new Glass(Math.random() * 100)); }
这些代码显然“过于复杂”,也是新类型加入时必须改动代码的场所之一。如果经常都要加入新类型,那么更好的方案就是建立一个独立的方法,用它获取所有必需的信息,并创建一个句柄,指向正确类型的一个对象——已经上溯造型到一个 Trash 对象。在《Design Patterns》中,它被粗略地称呼为“创建范式”。要在这里应用的特殊范式是 Factory 方法的一种变体。在这里,Factory 方法属于 Trash 的一名 static(静态)成员。但更常见的一种情况是:它属于衍生类中一个被过载的方法。
Factory 方法的基本原理是我们将创建对象所需的基本信息传递给它,然后返回并等候句柄(已经上溯造型至基础类型)作为返回值出现。从这时开始,就可以按多形性的方式对待对象了。因此,我们根本没必要知道所创建对象的准确类型是什么。事实上,Factory 方法会把自己隐藏起来,我们是看不见它的。这样做可防止不慎的误用。如果想在没有多形性的前提下使用对象,必须明确地使用 RTTI 和指定造型。
但仍然存在一个小问题,特别是在基础类中使用更复杂的方法(不是在这里展示的那种),且在衍生类里过载(覆盖)了它的前提下。如果在衍生类里请求的信息要求更多或者不同的参数,那么该怎么办呢?“创建更多的对象”解决了这个问题。为实现 Factory 方法,Trash 类使用了一个新的方法,名为 factory。为了将创建数据隐藏起来,我们用一个名为 Info 的新类包含 factory 方法创建适当的 Trash 对象时需要的全部信息。下面是 Info 一种简单的实现方式:
class Info { int type; // Must change this to add another type: static final int MAX_NUM = 4; double data; Info(int typeNum, double dat) { type = typeNum % MAX_NUM; data = dat; } }
Info 对象唯一的任务就是容纳用于 factory() 方法的信息。现在,假如出现了一种特殊情况,factory() 需要更多或者不同的信息来新建一种类型的 Trash 对象,那么再也不需要改动 factory() 了。通过添加新的数据和构建器,我们可以修改 Info 类,或者采用子类处理更典型的面向对象形式。
用于这个简单示例的 factory() 方法如下:
static Trash factory(Info i) { switch(i.type) { default: // To quiet the compiler case 0: return new Aluminum(i.data); case 1: return new Paper(i.data); case 2: return new Glass(i.data); // Two lines here: case 3: return new Cardboard(i.data); } }
在这里,对象的准确类型很容易即可判断出来。但我们可以设想一些更复杂的情况,factory() 将采用一种复杂的算法。无论如何,现在的关键是它已隐藏到某个地方,而且我们在添加新类型时知道去那个地方。
新对象在 main() 中的创建现在变得非常简单和清爽:
for(int i = 0; i < 30; i++) bin.addElement( Trash.factory( new Info( (int)(Math.random() * Info.MAX_NUM), Math.random() * 100)));
我们在这里创建了一个 Info 对象,用于将数据传入 factory();后者在内存堆中创建某种 Trash 对象,并返回添加到 Vector bin 内的句柄。当然,如果改变了参数的数量及类型,仍然需要修改这个语句。但假如 Info 对象的创建是自动进行的,也可以避免那个麻烦。例如,可将参数的一个 Vector 传递到 Info 对象的构建器中(或直接传入一个 factory() 调用)。这要求在运行期间对参数(自变量)进行分析与检查,但确实提供了非常高的灵活程度。
大家从这个代码可看出 Factory 要负责解决的“领头变化”问题:如果向系统添加了新类型(发生了变化),唯一需要修改的代码在 Factory 内部,所以 Factory 将那种变化的影响隔离出来了。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论