“建造更多的工具”
这样便引出了面向工具措施设计时一条通例的准则,我最早是在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将那种变革的影响断绝出来了。