意图
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,将一个构造复杂对象的过程和组合对象的部件解耦。
采用循环渐进的方式组合复杂的对象实例
适用性
在以下情况使用Builder模式:
1. 当创建复杂对象的算法应该独立与该对象的组成部分以及它们的装配方式时。
2. 当构造过程必须允许被构造的对象有不同的表现时。
3. 用来创建组合结构。
结构
参与者
Builder
1.为创建一个Product对象的各个部件指定抽象接口,规范产品对象的各个组成成分的建造,独立于业务逻辑
ConcreteBuilder
- 实现Builder的接口以构造和装配该产品的各个部件
- 定义并明确它所创建的表示
- 提供一个检索产品的接口
- 和业务逻辑紧密相关,并且在指导者的调用下创建产品实例
Director
1.构造一个使用Builder接口的对象
Product
- 表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程
- 包含定义组成组件的类,包括将这些部件装备成最终产品的接口。
代码
Product
@SuppressWarnings("serial")
public class Media<T> extends ArrayList<T>{}
@SuppressWarnings("serial")
class Book<T> extends Media<T>{}
@SuppressWarnings("serial")
class Magazine<T> extends Media<T>{}
@SuppressWarnings("serial")
class WebSite<T> extends Media<T>{}
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); }
}
Builder
public abstract class AbstractMediaBuilder {
public abstract void buildBase();
public abstract void addMediaItem(MediaItem mediaItem);
public abstract Media<MediaItem> getFinishedMedia();
}
ConcreteBuilder
public class BookBuilder extends AbstractMediaBuilder {
private Book<MediaItem> book;
public void buildBase() {
System.out.println("Building book framework");
book = new Book<MediaItem>();
}
public void addMediaItem(MediaItem chapter) {
System.out.println("Adding chapter " + chapter);
book.add(chapter);
}
public Media<MediaItem> getFinishedMedia() {
return book;
}
}
public class MagazineBuilder extends AbstractMediaBuilder {
private Magazine<MediaItem> magazine;
public void buildBase() {
System.out.println("Building magazine framework");
magazine = new Magazine<MediaItem>();
}
public void addMediaItem(MediaItem article) {
System.out.println("Adding article " + article);
magazine.add(article);
}
public Media<MediaItem> getFinishedMedia() {
return magazine;
}
}
Director
public class MediaDirector {
private AbstractMediaBuilder abstractMediaBuilder;
public MediaDirector(AbstractMediaBuilder abstractMediaBuilder){
this.abstractMediaBuilder = abstractMediaBuilder;
}
public Media<MediaItem> produceMedia(List<MediaItem> input) {
abstractMediaBuilder.buildBase();
for(MediaItem mediaItem:input){
abstractMediaBuilder.addMediaItem(mediaItem);
}
return abstractMediaBuilder.getFinishedMedia();
}
}
Client
public class Test {
public static void main(String[] args) {
List<MediaItem> input = Arrays.asList(new MediaItem[] {
new MediaItem("item1"), new MediaItem("item2"),
new MediaItem("item3"), new MediaItem("item4"),
});
AbstractMediaBuilder book = new BookBuilder();
AbstractMediaBuilder magazine = new MagazineBuilder();
MediaDirector bookd = new MediaDirector(book);
bookd.produceMedia(input);
MediaDirector magazined = new MediaDirector(magazine);
magazined.produceMedia(input);
}
}
协作
- 客户创建Director对象,并用它所需要的Builder对象进行配置
- 一旦产品部件被生成,导向器就会通知生成器
- 生成器处理导向器的请求,并将部件添加到该产品中
- 客户从生成器中检索产品
效果
可以改变一个产品的内部表示
Builder对象提供给导向器一个构造产品的抽象接口。该接口使得生成器可以隐藏这个产品的表示和内部结构。它同时也隐藏了该产品是如何装配的。因为产品是通过抽象接口构造的,你在改变该产品的内部表示时所要做的只是定义一个新的生成器。
将构造代码和表示代码分离
Builder模式通过封装一个复杂对象的创建和表示方式提高了对象的模块性。客户不需要知道定义产品内部结构的类的所有信息;这些类是不会出现在Builder接口中的。每个ConcreteBuilder包含创建和装配一个特定产品的所有代码。这些代码只需要写一次;然后不同的Director可以复用它以在相同部件集合的基础上构作不同的Product。
使你可对构造过程进行更精细的控制
Builder模式与一下子就生成产品的创建型模式不同,它是在导向者的控制下一步一步构造产品的。仅当该产品完成时导向者才从生成器中取回它。因此Builder接口相比其他创建型模式能更好的反映产品的构造过程。这使你可以更精细的控制构件过程,从而能更精细的控制所得产品的内部结构。
优点
- 将一个复杂对象的创建过程封装起来
- 允许对象通过多个步骤来创建,并且可以改变创建过程
- 向客户隐藏内部的表现
- 产品的实现可以被替换,因为客户只看到一个抽象的接口
缺点
与工厂模式相比,采用生成器模式创建对象更复杂,其客户,需要更多的知识领域。
实现
通常有一个抽象的Builder类为导向者可能要求创建的每一个构件定义一个操作。这些操作缺省情况下什么都不做。一个ConcreteBuilder类对它有兴趣创建的构建重新定义这些操作。
装配和构造接口
生成器逐步的构造它们的产品。因此Builder类接口必须足够普通,以便为各种类型的具体生成器构造产品。
一个关键的设计问题在于构造和装配过程的模型。构造请求的结构只是添加到产品中,通常这样的模型就已足够了。
但有时你可能需要访问前面已经构造了的产品部件。在这种情况下,生成器将子结点返回给导向者,然后导向者将它们回传给生成这去创建父结点。
为什么产品没有抽象类
通常情况下,由具体生成器生成的产品,它们的表示相差是如此之大以至于给不同的产品以公共父类没有太大的意思。
在Builder中缺省的方法为空
C++中,生成方法故意不声明为纯虚成员函数,而是把它们定义为空方法,这使客户只重定义它们所感兴趣的操作。
经典例子
电脑组装(商务型、娱乐游戏型、家用型)
创建模式着重于逐渐将组件装配成一个产品并向外提供产品,通过相同的创建过程创建不同的对象,并且不直接返回
抽象工厂模式着重于得到产品族相关的多个产品对象,直接返回对象,并且强调的是创建多个相关依赖的对象提供一个统一的接口。
相关模式
Template Method Pattern
在构建模式中,Director参与者控制Builder参与者;在模板模式中则是父类控制子类。
Facade Pattern
构建模式的指导者是组合构建者所提供的复杂方法,在把构成对象实例的接口提供给外部;而Facade Pattern的Facade参与者是组合内部模块再把执行操作的简单接口提供给外部。
Abstract Factory Pattern
抽象工厂模式与Builder相似,因为它也可以创建复杂对象。主要的区别是Builder模式着重于一步步构造一个复杂对象。而Abstract Factory着重于多个系列的产品对象(简单的或是复杂的)。Builder在最后的一步返回产品,而对于Abstract Factory来说,产品是立即返回的。
Composite Pattern
Composite通常是用Builder生成的。利用构建模式所产生的结果可能会变成组合模式。
敬请期待“原型模式(Prototype Pattern对象创建型模式)”