建造模式是对象的创建模式。
建造模式可以将一个产品的内部表象和产品的生成过程分割开来,
从而可以使一个建造过程生成具有不同的内部表象的产品对象。
不同的产品可以有不同的内部表象,也就是有不同的零件。
对象性质的建造
有些情况条,一个对象会有一些重要的性质,在它们没有恰当的值之前,对象不能作为一个完整的产品使用。
比如,一个电子邮件发件人地址,收件人地址,主题,内容,附录等部分,在收件人地址得到赋值之前,这个电子邮件不能发出。
有些情况下,一个对象的一些性质必须按照某个顺序赋值才有意义。在某个性质没有赋值之前,另一个性质则无法赋值。
这时候,此对象相当于一个有待建造的产品,而对象的这些性质相当于产品的零件,建造产品的过程是建造零件的过程。
建造模式非常适用于此种情况。
建造者模式将产品的结构和产品的零件建造过程对客户端隐藏起来,
把对建造过程进行指挥的责任和具体建造者零件的责任分割开来,达到责任划分和封装的目的。
建造者模式的结构
这个模式涉及到四个角色:
- 抽象建造者角色(Builder): 给出一个抽象接口,以规范产品对象的各个组成成分的建造。定义了两种方法:1. 建造零件方法;2.结果返还方法。一般来说,产品所包含的零件数目与建造方法的数据相符。
- 具体建造者角色(Concrete Builder): 这个角色要完成的任务包括:1. 实现抽象建造者 Builder 所声明的接口,给出一步一步的完成创建产品实例的操作。2.在建造过程完成后,提供产品的实例。
- 导演者角色(Director): 担任这个角色的类调用具体建造者角色以创建产品对象。应对指出的是,导演这角色并没有产品类的具体知识,正则拥有产品类的具体知识的是具体建造者角色。
- 产品角色(Product): 产品便是建造中的复杂对象。一般来说,一个系统中会有多于一个的产品类,而且这些产品类并不一定有共同的接口,而完全可以是不相关联的。
源代码
多个产品类的情况
接口标识的应用
应当注意的是,retrieveProduct() 方法是抽象建造者角色提供的,如果它返还的是 Product1类型或Product2类型的话,
那么ConcreteBuilder2或者Concretebuilder1就会有问题,因为它们应当返还Product1和Product2类型。
解决的方案是为两个具体产品类提供一个共同的接口,形成它们共同的类型。由于建造模式的产品类往往是没有太多关系的一些类,因为,它们不太可能有共同的接口。因此,使用一个标识接口为所有的具体产品类提供一个共同的类型就成为解决问题的方案,即所有的retrieveProduct()都返还Product类型就可以了。
建造模式的活动序列
建造模式的实现
建造模式在实现时可以根据具体情况做一些变化。
1. 省略抽象建造者角色:如果系统只需要一个具体建造者角色的话,可以省略掉抽象建造者角色。抽象建造者角色存在的目的是规范具体建造者角色的行为。只有一个具体建造者,就不需要了。
2. 省略导演者角色
在具体建造者只有一个的情况下,如果抽象建造者角色已经被省略掉,那么还可以进一步省略掉导演者角色。
JavaMail中的建造模式
JavaMail大量使用抽象工厂模式和其他设计模式,包括建造模式。
JavaMail中的Message和MmeMessage 等类均是退化的建造模式的应用。JavaMail的使用如下:
作为客户端和导演对象,MailSender通过一步步的提供 MimeMessage 对象的零件性质,也就是from, recipient, subject, text等,最后得到整个产品对象,也就是 MimeMessage对象。
代码清单如下:
一个发送邮件的例子
产品类
应当指出的是,虽然在这个例子里各个产品类均有一个共同的接口,但这仅仅是本例子特有的,
并不代表建造模式的特点。建造模式可以应用到具有完全不同接口的产品类上。
系统类图
代码清单:
WelcomeMessage的源代码
GoodbyeMessage类的源代码
导演类 Director 的源代码
抽象建造者类 Builder 的源代码
具体建造者类WelcomeBuilder的源代码
具体建造者类 GoodbyeBuilder 的源代码
客户端 Client类的源代码
系统的时序图
在什么情况下使用建造模式
- 需要生成的产品对象有复杂的内部结构。每个内部成分本身可以是对象,也可以仅仅是一个对象的组成成分。
- 需要生成的产品对象的属性相互依赖。
- 在对象创建过程中会使用到系统中的其他一些对象,这些对象在产品对象的创建过程中不易得到。
同时,使用建造模式主要有以下效果:
- 建造模式的使用使得产品的内部表象可以独立的变化。使用建造模式可以使客户端不必知道产品内部组成的细节 。
- 每一个 Builder 都相对独立, 而与其他的 Builder 无关。
- 模式所建造的最终产品更易于控制。