(Specialized creation)
(Prototype)
通过克隆一个原型的实例来创建对象。“模式重构”章节会有一个例子。
(Builder)
构造器的目的是从“表示”中分离构造,允许同一个构造多个不同的表示。构造过程保持相似,但是结果对象有不同的可能表示。GoF指出构造模式与抽象工厂主要的不同在于构造器一步一步地创建对象,因此创建过程及时的展开看起来是重要的。此外,看起来“指导者”取得传递到构造器的片段流,并且每一个片段被用来执行一个构造过程的步骤。
GoF中给的一个例子:文本格式转换。输入格式为 RTF,一旦它被解析,指示就会被传递到文本转换器,转换器以不同的方式实现,依赖于结果格式是ASCII,Tex,或者一个GUI文本。尽管结果“对象”(完全转换的文本文件)随着时间的过去被创建,如果你把每次RTF指示看作一个对象,对我来说这更像连接桥模式,因为特定类型的转换扩展了基类的接口。并且一般的问题解决方案将允许多个读者在“前端”并且多个转换器在“后端”,这是连接桥模式的主要特点。
对我来说,构造器用多个步骤创建一个对象,并且那些步骤被构造器对象外部访问,是区分它(结构的)与一般工厂的要点。然而,GoF强调你能够用同样的过程创建不同的表示。它们从来没有明确的定义通过表示层它们意味着什么。(表示层包含一个太大的对象吗?如果表示被分解成许多小对象构造器的需要会消失吗?)
GoF中的另一个例子创建了一个迷宫对象,添加房间到迷宫并且添加门到房间。这是一个多步骤的过程,但是,不同的表示是“标准的”和“复杂的”迷宫-----并非真正不同种类的迷宫,而是不同的复杂程度。我尝试去创建一个迷宫对象构造器能够控制任意复杂的迷宫。迷宫对象的最终变化不会创建所有的迷宫,而是在一个存在的迷宫中计数房间。
RTF转换器和Mazebuilder例子对构造器来说都不能算是一个完全符合的例子。读者曾经建议Sax XML解析器的输出,和标准的编译器解析,也许可以自然的被归类到构造器中。
这有个例子也许或多或少的有那么点意思,至少给出了给多思想关于构造器想要做什么?媒体也许会被构造成不同的表示,比如书籍,杂志,和网站。这个例子论证包含的步骤是一样的,并且因此能够抽象到指示器类中。
//: builder:BuildMedia.java
// Example of the Builder pattern
package builder;
import java.util.*;
import junit.framework.*;
// Different "representations" of media:
class Media extends ArrayList {}
class Book extends Media {}
class Magazine extends Media {}
class WebSite extends Media {}
// ... contain different kinds of media items:
class MediaItem {
private String s;
public MediaItem(String s) { this.s = s; }
public String toString() { return s; }
}
class Chapter extends MediaItem {
public Chapter(String s) { super(s); }
}
class Article extends MediaItem {
public Article(String s) { super(s); }
}
class WebItem extends MediaItem {
public WebItem(String s) { super(s); }
}
// ... but use the same basic construction steps:
class MediaBuilder {
public void buildBase() {}
public void addMediaItem(MediaItem item) {}
public Media getFinishedMedia() { return null; }
}
class BookBuilder extends MediaBuilder {
private Book b;
public void buildBase() {
System.out.println("Building book framework");
b = new Book();
}
public void addMediaItem(MediaItem chapter) {
System.out.println("Adding chapter " + chapter);
b.add(chapter);
}
public Media getFinishedMedia() { return b; }
}
class MagazineBuilder extends MediaBuilder {
private Magazine m;
public void buildBase() {
System.out.println("Building magazine framework");
m = new Magazine();
}
public void addMediaItem(MediaItem article) {
System.out.println("Adding article " + article);
m.add(article);
}
public Media getFinishedMedia() { return m; }
}
class WebSiteBuilder extends MediaBuilder {
private WebSite w;
public void buildBase() {
System.out.println("Building web site framework");
w = new WebSite();
}
public void addMediaItem(MediaItem webItem) {
System.out.println("Adding web item " + webItem);
w.add(webItem);
}
public Media getFinishedMedia() { return w; }
}
class MediaDirector { // a.k.a. "Context"
private MediaBuilder mb;
public MediaDirector(MediaBuilder mb) {
this.mb = mb; // Strategy-ish
}
public Media produceMedia(List input) {
mb.buildBase();
for(Iterator it = input.iterator(); it.hasNext();)
mb.addMediaItem((MediaItem)it.next());
return mb.getFinishedMedia();
}
};
public class BuildMedia extends TestCase {
private List input = Arrays.asList(new MediaItem[] {
new MediaItem("item1"), new MediaItem("item2"),
new MediaItem("item3"), new MediaItem("item4"),
});
public void testBook() {
MediaDirector buildBook =
new MediaDirector(new BookBuilder());
Media book = buildBook.produceMedia(input);
String result = "book: " + book;
System.out.println(result);
assertEquals(result,
"book: [item1, item2, item3, item4]");
}
public void testMagazine() {
MediaDirector buildMagazine =
new MediaDirector(new MagazineBuilder());
Media magazine = buildMagazine.produceMedia(input);
String result = "magazine: " + magazine;
System.out.println(result);
assertEquals(result,
"magazine: [item1, item2, item3, item4]");
}
public void testWebSite() {
MediaDirector buildWebSite =
new MediaDirector(new WebSiteBuilder());
Media webSite = buildWebSite.produceMedia(input);
String result = "web site: " + webSite;
System.out.println(result);
assertEquals(result,
"web site: [item1, item2, item3, item4]");
}
public static void main(String[] args) {
junit.textui.TestRunner.run(BuildMedia.class);
}
} ///:~
注意:在某种方式这个能够看做一个更复杂的状态模式,因为指示器的行为依赖于你使用的构造器的类型。简单的转向请求通过底层的状态对象 ,然而,指示器有一系列操作去执行,并且它应用状态对象作为一个策略来满足它的工作。这样,构造器也能够被描述当使用一个策略去创建对象的时候。
练习
1.拆分一个文本文件到一个单词组的输入流中(考虑使用正则表达式)。创建一个构造器把这些单词放到java.util.TreeSet中,另外一个使用java.util.HashMap包含单词和这些单词出现的次数(单词计数器)。omencathay译
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/25966/viewspace-53318/,如需转载,请注明出处,否则将追究法律责任。