建造者模式的定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。简言之,将构造复杂对象的过程和组成对象的部件解耦。
当要生成的产品有复杂的内部结构——比如由多个对象组成;而系统中对此产品的需求将来可能要改变产品对象的内部结构的构成,比如说产品的一些属性现在由一个小对象组 成,而更改后的型号可能需要 N个小对象组成;而且不能将产品的内部构造完全暴露给客 户程序,一是为了可用性,二是为了安全等因素。满足上面的设计环境就可以考虑使用建造模式来搭建框架了。
(一)建造者模式的组成结构
1) 抽象建造者角色(Builder):这个角色用来规范产品对象的各个组成成分的建造。一般而言,此角色独立于应用程序的业务逻辑。
2) 具体建造者角色(ConcreteBuilder):担任这个角色的是于应用程序紧密相关的类,它们在指导者的调用下创建产品实例。这个角色在实现抽象建造者角色提供的方法的前提下,达到完成产品组装,提供成品的功能。
3) 指导者角色(Director):调用具体建造者角色以创建产品对象。指导者并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者对象。
4) 产品角色(Product):建造中的复杂对象。它要包含那些定义组件的类,包括将这些组件装配成产品的接口。
类图:
(二)建造者模式示例代码
产品角色:Media ,Book,Magazine ,MediaItem ,Chapter ,Article
//父类 媒体
public class Media extends ArrayList {}
//书籍类
public class Book extends Media {}
//杂志类
public class Magazine extends Media {}
//父类 媒体项目
public class MediaItem {
private String s;
public MediaItem(String s) {
this.s = s;
}
public String toString() {
return s;
}
}
//书籍的组成部分 章节
public class Chapter extends MediaItem {
public Chapter(String s) {
super(s);
}
}
//杂志的组成部分 文章
public class Article extends MediaItem {
public Article(String s) {
super (s);
}
}
抽象建造者角色 – MediaBuilder
它规范了所有媒体建造的步骤
//所有媒体建造者
public interface MediaBuilder {
void buildBase();
void addMediaItem(MediaItem item);
Media getFinishedMedia();
}
具体建造者角色 – BookBuilder,MagazineBuilder
//书籍建造者
public class BookBuilder implements 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;
}
}
//杂志建造者
public class MagazineBuilder implements 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;
}
}
指导者角色 – MediaDirector
指导建造的细节
//媒体指导者
public class MediaDirector {
private MediaBuilder mb;
public MediaDirector(MediaBuilder mb) {
this.mb = mb; //具有策略模式相似特征的
}
public Media produceMedia(List input) {
mb.buildBase ();
for (Iterator it = input.iterator (); it.hasNext (); )
mb.addMediaItem ((MediaItem) it.next ());
return mb.getFinishedMedia ();
}
}
测试程序:
import java.util.Arrays;
import java.util.List;
public class Main 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 static void main(String[] args) {
junit.textui.TestRunner.run(Main.class);
}
}
输出结果:
(三)建造者模式的特点
①建造模式可以使得产品内部的表象独立变化。在原来的工厂方法模式中,产品内部的表象是由产品自身来决定的;而在建造模式中则是“外部化”为由建造者来负责。这样定义一个新的具体建造者角色就可以改变产品的内部表象,符合“开闭原则”。
②建造模式使得客户不需要知道太多产品内部的细节。它将复杂对象的组建和表示方式封装在一个具体的建造角色中,而且由指导者来协调建造者角色来得到具体的产品实例。
③每一个具体建造者角色是毫无关系的。
④建造模式可以对复杂产品的创建进行更加精细的控制。产品的组成是由指导者角色调用具体建造者角色来逐步完成的,所以比起其它创建型模式能更好的反映产品的构造过程。
(四)关于扩展建造者模式
建造模式中很可能要用到组成成品的各种组件类,对于这些类的创建可以考虑使用工厂方法或者原型模式来实现,在必要的时候也可以加上单例模式来控制类实例的产生。但是要坚持一个大前提就是要使引入的模式给你的系统带来好处,而不是臃肿的结构。
建造模式在得到复杂产品的时候可能要引用多个不同的组件,在这一点上来看,建造模式和抽象工厂模式是相似的。可以从以下两点来区分两者:创建模式着重于逐步将组件装配成一个成品并向外提供成品,而抽象工厂模式着重于得到产品族中相关的多个产品对象;抽象工厂模式的应用是受限于产品族的,建造模式则不会。由于建造模式和抽象工厂模式在实现功能上相似,所以两者使用的环境都比较复杂并且需要更多的灵活性。组合模式中的树枝构件角色(Composite)往往是由多个树叶构件角色(Leaf)组成,因此树枝构件角色的产生可以由建造模式来担当。