概述
在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定。如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的 “稳定构建算法”不随着需求改变而改变?这就是要说的建造者模式。
本文通过现实生活中的买KFC的例子,用图解的方式来诠释建造者模式。
意图
将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
模型图
在构造一个对象的时候,往往有很多复杂的过程和次序,例如建造一个机器人,那要先造头,还是要先造身子,这就关乎到一个制造工序的问题。其实建造者模式和工厂模式是很接近的,但是,建造者模式提供了一个更加细粒度的对象的建造过程。
建造者模式的几种演化
省略抽象建造者角色
系统中只需要一个具体建造者,省略掉抽象建造者,结构图如下:
指导者代码如下:
2 {
3 private ConcreteBuilder builder;
4
5 public void Construct()
6 {
7 builder.BuildPartA();
8 builder.BuildPartB();
9 }
10 }
省略指导者角色
抽象建造者角色已经被省略掉,还可以省略掉指导者角色。让Builder角色自己扮演指导者与建造者双重角色。结构图如下:
建造者角色代码如下:
2 {
3 private Product product = new Product();
4
5 public void BuildPartA()
6 {
7 //
8 }
9
10 public void BuildPartB()
11 {
12 //
13 }
14
15 public Product GetResult()
16 {
17 return product;
18 }
19
20 public void Construct()
21 {
22 BuildPartA();
23 BuildPartB();
24 }
25 }
客户程序:
2 {
3 private static Builder builder;
4
5 public static void Main()
6 {
7 builder = new Builder();
8 builder.Construct();
9 Product product = builder.GetResult();
10 }
11 }
合并建造者角色和产品角色
建造模式失去抽象建造者角色和指导者角色后,可以进一步退化,从而失去具体建造者角色,此时具体建造者角色和产品角色合并,从而使得产品自己就是自己的建造者。这样做混淆了对象的建造者和对象本身,但是有时候一个产品对象有着固定的几个零件,而且永远只有这几个零件,此时将产品类和建造类合并,可以使系统简单易读。结构图如下:
实现要点
1、建造者模式主要用于“分步骤构建一个复杂的对象”,在这其中“分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化。
2、产品不需要抽象类,特别是由于创建对象的算法复杂而导致使用此模式的情况下或者此模式应用于产品的生成过程,其最终结果可能差异很大,不大可能提炼出一个抽象产品类。
3、创建者中的创建子部件的接口方法不是抽象方法而是空方法,不进行任何操作,具体的创建者只需要覆盖需要的方法就可以,但是这也不是绝对的,特别是类似文本转换这种情况下,缺省的方法将输入原封不动的输出是合理的缺省操作。
4、前面我们说过的抽象工厂模式(Abtract Factory)解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化,建造者模式常和组合模式(Composite Pattern)结合使用。
效果
1、建造者模式的使用使得产品的内部表象可以独立的变化。使用建造者模式可以使客户端不必知道产品内部组成的细节。
2、每一个Builder都相对独立,而与其它的Builder无关。
3、可使对构造过程更加精细控制。
4、将构建代码和表示代码分开。
5、建造者模式的缺点在于难于应付“分步骤构建算法”的需求变动。
适用性
以下情况应当使用建造者模式:
1、需要生成的产品对象有复杂的内部结构。
2、需要生成的产品对象的属性相互依赖,建造者模式可以强迫生成顺序。
3、 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
应用场景
1、 RTF文档交换格式阅读器。
2、 .NET环境下的字符串处理StringBuilder,这是一种简化了的建造者模式。
3、 ……
总结
建造者模式的实质是解耦组装过程和创建具体部件,使得我们不用去关心每个部件是如何组装的。