

























设计模式----建造者模式(Builder Pattern)
概述:
在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定。如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?这就是要说的建造者模式。
现实中的例子:
就拿学校来说吧,每到期末考试完成之后,老师要批改试卷,得到每个学生的期末考试成绩,而老师批改试卷这个过程不变化的,都要经过(批改试卷、统计分数、把分数上传到教务处)。每个老师都要经过这样一个步骤,而变化是其中的子过程,如:批改的是《英语》或者《数学》,统计分数的时候,可以将分数记录到纸张上,也可以用一个EXCEL文档保存起来等等。
意图:
将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示
--《设计模式》GOF
UML类图:

其中的类或对象之间的关系为:
Builder:抽象建造者
为创建一个Product对象的各个部件指定抽象接口。
ConcreteBuilder:具体建造者
1.实现Builder接口,构造和装配产品的各个部件.
2.定义并明确它所创建的表示.
3.提供一个返回这个产品的接口。
Director:指挥者
构建一个使用Builder接口的对象。
Product:产品角色
1.被构建的复杂对象,具体建造者创建该产品的内部表示并表示定义它的装配过程。
2.包含定义组成部件的类,包括将这些部件装配成最终产品的接口。
例子:
类关系图如下:

抽象建造者:
1
//======================================================================
2
//
3
// Copyright (C) 2007-2008 三月软件工作室
4
// All rights reserved
5
//
6
// filename :Builder
7
// description :
8
//
9
// created by 侯垒 at 07/20/2008 10:24:59
10
// http://houleixx.cnblogs.com
11
//
12
//======================================================================
13
14
using System;
15
using System.Collections.Generic;
16
using System.Text;
17
18
namespace Builder_Pattern
19
{
20
/*
21
* 抽象建造者具有四个方法:
22
*
23
* 装配框架
24
* 装配发动机
25
* 装配轮子
26
* 装配车门
27
*/
28
29
/// <summary>
30
/// 抽象建造者;
31
/// </summary>
32
abstract public class Builder
33
{
34
protected Product vehicle;
35
36
/// <summary>
37
/// 车辆属性;
38
/// </summary>
39
public Product Vehicle
40
{
41
get
42
{
43
return vehicle;
44
}
45
46
}
47
48
abstract public void BuildFrame();
49
abstract public void BuildEngine();
50
abstract public void BuildWheels();
51
abstract public void BuildDoors();
52
}
53
}
54
具体建造者:
自行车建造者
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
5
namespace Builder_Pattern
6
{
7
/// <summary>
8
/// 自行车类;
9
/// </summary>
10
public class BikeBuilder : Builder
11
{
12
/// <summary>
13
/// 构造自行车框架;
14
/// </summary>
15
public override void BuildFrame()
16
{
17
vehicle = new Product("自行车");
18
vehicle["frame"] = "自行车框架";
19
}
20
21
/// <summary>
22
/// 构造自行车发动机;
23
/// </summary>
24
public override void BuildEngine()
25
{
26
vehicle["engine"] = "none";
27
}
28
29
/// <summary>
30
/// 构造自行车轮子;
31
/// </summary>
32
public override void BuildWheels()
33
{
34
vehicle["wheels"] = "2";
35
}
36
37
/// <summary>
38
/// 构造自行车门;
39
/// </summary>
40
public override void BuildDoors()
41
{
42
vehicle["doors"] = "0";
43
}
44
}
45
}
46
摩托车建造者
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
5
namespace Builder_Pattern
6
{
7
/// <summary>
8
/// 摩托车类;
9
/// </summary>
10
public class MotorCycleBuilder : Builder
11
{
12
/// <summary>
13
/// 构造摩托车框架;
14
/// </summary>
15
public override void BuildFrame()
16
{
17
vehicle = new Product("摩托车");
18
vehicle["frame"] = "摩托车框架";
19
}
20
21
/// <summary>
22
/// 构造摩托车发动机;
23
/// </summary>
24
public override void BuildEngine()
25
{
26
vehicle["engine"] = "摩托车发动机";
27
}
28
29
/// <summary>
30
/// 摩托车轮数;
31
/// </summary>
32
public override void BuildWheels()
33
{
34
vehicle["wheels"] = "2";
35
}
36
37
/// <summary>
38
/// 摩托车门;
39
/// </summary>
40
public override void BuildDoors()
41
{
42
vehicle["doors"] = "0";
43
}
44
}
45
}
46
汽车建造者
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
5
namespace Builder_Pattern
6
{
7
/// <summary>
8
/// 汽车类;
9
/// </summary>
10
public class CarBuilder : Builder
11
{
12
13
/// <summary>
14
/// 构造汽车框架;
15
/// </summary>
16
public override void BuildFrame()
17
{
18
vehicle = new Product("汽车");
19
vehicle["frame"] = "汽车框架";
20
}
21
22
/// <summary>
23
/// 汽车发动机;
24
/// </summary>
25
public override void BuildEngine()
26
{
27
vehicle["engine"] = "汽车发动机";
28
}
29
30
/// <summary>
31
/// 汽车门数;
32
/// </summary>
33
public override void BuildWheels()
34
{
35
vehicle["wheels"] = "4";
36
}
37
38
/// <summary>
39
/// 汽车轮数;
40
/// </summary>
41
public override void BuildDoors()
42
{
43
vehicle["doors"] ="4";
44
}
45
}
46
}
47
指导者
1
//======================================================================
2
//
3
// Copyright (C) 2007-2008 三月软件工作室
4
// All rights reserved
5
//
6
// filename :Director
7
// description :
8
//
9
// created by 侯垒 at 07/20/2008 10:24:06
10
// http://houleixx.cnblogs.com
11
//
12
//======================================================================
13
14
using System;
15
using System.Collections.Generic;
16
using System.Text;
17
18
namespace Builder_Pattern
19
{
20
/// <summary>
21
/// 指挥者;
22
/// </summary>
23
class Director
24
{
25
/// <summary>
26
/// 构造车辆;
27
/// </summary>
28
/// <param name="builder">要构造的车辆</param>
29
public void Construct(Builder builder)
30
{
31
builder.BuildFrame();
32
builder.BuildEngine();
33
builder.BuildWheels();
34
builder.BuildDoors();
35
}
36
}
37
}
38
具体产品
1
//======================================================================
2
//
3
// Copyright (C) 2007-2008 三月软件工作室
4
// All rights reserved
5
//
6
// filename :Product
7
// description :
8
//
9
// created by 侯垒 at 07/20/2008 10:27:47
10
// http://houleixx.cnblogs.com
11
//
12
//======================================================================
13
14
using System;
15
using System.Collections.Generic;
16
using System.Collections;
17
using System.Text;
18
19
namespace Builder_Pattern
20
{
21
/// <summary>
22
/// 具体的产品,指车辆;
23
/// </summary>
24
public class Product
25
{
26
private string type;
27
public Product(string type)
28
{
29
this.type = type;
30
}
31
private Hashtable parts = new Hashtable();
32
33
//应用索引器;
34
public object this[string key]
35
{
36
get
37
{
38
return parts[key];
39
}
40
set
41
{
42
parts[key] = value;
43
}
44
}
45
/// <summary>
46
/// 显示车辆信息;
47
/// </summary>
48
public void Show()
49
{
50
Console.WriteLine("------------------------------------");
51
Console.WriteLine("车辆类型:" + type);
52
Console.WriteLine("框架:" + parts["frame"]);
53
Console.WriteLine("发动机:" + parts["engine"]);
54
Console.WriteLine("轮子数:" + parts["wheels"]);
55
Console.WriteLine("车门数:" + parts["doors"]);
56
}
57
}
58
}
59
客户端调用
1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4
5
namespace Builder_Pattern
6
{
7
class Program
8
{
9
static void Main(string[] args)
10
{
11
Director director = new Director();//指挥者;
12
13
Builder builderBike = new BikeBuilder();
14
Builder builderMotor = new MotorCycleBuilder();
15
Builder builderCar = new CarBuilder();
16
17
//自行车;
18
director.Construct(builderBike);
19
builderBike.Vehicle.Show();
20
21
//摩托车;
22
director.Construct(builderMotor);
23
builderMotor.Vehicle.Show();
24
25
//汽车;
26
director.Construct(builderCar);
27
builderCar.Vehicle.Show();
28
29
Console.Read();
30
}
31
}
32
}
33
为什么需要Director:
在这个模式中,Director类好像是一个多余的类,在应用中的作用好像并不大。其实它的作用是明显的。第一,它隔离了客户及生产过程。第二,它负责控制产品的生成过程。比如你是客户,你要买汽车,你选好车型、颜色、内外装饰等,交给Director,Director告诉你去某车间取车就可以。这样其作用大家都能体会出来了吧。
建造者模式的演变:
往往在现实中为了达到灵活应用的目的,Director类有时候也可省略不写,故建造者模式也有以下几种演变:
省略抽象建造者角色:
指导者代码如下:
1
public void Construct(ConcreteBuilder builder)
2
{
3
builder.BuildPartA();
4
builder.BuildPartB();
5
}
6
省略指导者角色:
抽象建造者角色已经被省略掉,还可以省略掉指导者角色。让Builder角色自己扮演指导者与建造者双重角色。结构图如下:

建造者角色代码如下:
1
public class Builder
2
{
3
private Product product = new Product();
4
public void BuildPartA()
5
{
6
//
7
}
8
public void BuildPartB()
9
{
10
//
11
}
12
public Product GetResult()
13
{
14
return product;
15
}
16
public void Construct()
17
{
18
BuildPartA();
19
BuildPartB();
20
}
21
}
22
客户端程序:
1
public class Client
2
{
3
private Builder builder;
4
public static void Main()
5
{
6
Builder builder = new Builder();
7
builder.Construct();
8
Product product =builder.GetResult();
9
}
10
}
11
合并建造者角色和产品角色:
建造模式失去抽象建造者角色和指导者角色后,可以进一步退化,从而失去具体建造者角色,此时具体建造者角色和产品角色合并,从而使得产品自己就是自己的建造者。这样做混淆了对象的建造者和对象本身,但是有时候一个产品对象有着固定的几个零件,而且永远只有这几个零件,此时将产品类和建造类合并,可以使系统简单易读。结构图如下:
Builder模式与AbstractFactory模式的区别:
建造者模式(Builder)与抽象工厂模式很相象,但是,Builder返回完整的一个产品,而AbstractFactory返回一系列有关系的产品;在抽象工厂模式中,客户采用AbstractFactory生成自己要用的对象,而在建造者模式中,客户指导Builder类如何生成对象,或者如何合成一些类来构成建造类,侧重于一步步构造一个复杂对象,然后将结果返回。
实现要点:
1、建造者模式主要用于“分步骤构建一个复杂的对象”,在这其中“分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化。
2、产品不需要抽象类,特别是由于创建对象的算法复杂而导致使用此模式的情况下或者此模式应用于产品的生成过程,其最终结果可能差异很大,不大可能提炼出一个抽象产品类。
3、创建者中的创建子部件的接口方法不是抽象方法而是空方法,不进行任何操作,具体的创建者只需要覆盖需要的方法就可以,但是这也不是绝对的,特别是类似文本转换这种情况下,缺省的方法将输入原封不动的输出是合理的缺省操作。
4、前面我们说过的抽象工厂模式(Abtract Factory)解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化,建造者模式常和组合模式(Composite Pattern)结合使用。
效果:
1、建造者模式的使用使得产品的内部表象可以独立的变化。使用建造者模式可以使客户端不必知道产品内部组成的细节。
2、每一个Builder都相对独立,而与其它的Builder无关。
3、可使对构造过程更加精细控制。
4、建造者模式的缺点在于难于应付“分步骤构建算法”的需求变动。
适用性:
1、需要生成的产品对象有复杂的内部结构。
2、需要生成的产品对象的属性相互依赖,建造者模式可以强迫生成顺序。
3、在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
总结:
建造者模式的实质是解耦组装过程和创建具体部件,使得我们不用去关心每个部件是如何组装的。
参考:
1.《深入浅出设计模式(C#/Java版)》
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。