2.2 Builder(生成器)
不少朋友都看过《伯恩的身份》这部电影吧,即使没看过的朋友也至少应该听说过“特工”这种职业吧,我们不管特工枪法有多准、杀人的招数有多酷,但至少作为一个特工,没个三五本护照和身份证你都不好意思跟别人打招呼。那么我们就借用这样一个办证的场景来描述一下什么是Builder(生成器)模式吧。办证本就是一件技术活儿,绝不是把个人信息往小纸片上一填就完事儿的,需要经过很多复杂的工序,我个人觉得正恰好符合Builder模式所描述的场景。
伯恩的身份可以是一致的,例如:
1: public class IdentityProperty
2: {
3: public string SerialNumber { get; set; }
4: public string Name { get; set; }
5: public string Nationality { get; set; }
6: // Some other information.
7: }
但不同的国家对身份证上的信息表现方式以及防伪标志等制作工艺都有许多不同的方式和要求,因此我们在办证的时候就不能用一台机器给伯恩制作出所有国家的身份证(理论上可以,但这样的机器极难维护)。我们就不得不像显微镜那样,在不同的需要的情况下切换不同倍数的镜头,我们采用这种方式,为不同国家提供不同的制作方式,但都基于伯恩的身份信息。虽然身份证的制作工艺千差万别,但我们可以采用一台扫描仪来对其进行扫描检查,接下来请看我们的代码如何来实现这些细节吧:
1: using System;
2:
3: namespace Autumoon.DesignPatterns.Builder
4: {
5: public class IdentityProperty
6: {
7: public string SerialNumber { get; set; }
8: public string Name { get; set; }
9: public string Nationality { get; set; }
10: }
11:
12: public abstract class AbstractBuilder
13: {
14: public abstract object CreateAmericanIDCard(IdentityProperty idProperty);
15: public abstract object CreateChineseIDCard(IdentityProperty idProperty);
16: public abstract object CreateFrenchIDCard(IdentityProperty idProperty);
17: }
18:
19: public class IdentityBuilder : AbstractBuilder
20: {
21: public override object CreateAmericanIDCard(IdentityProperty idProperty)
22: {
23: // TODO: Invoke the special method to create an American ID card.
24:
25: return new object();
26: }
27:
28: public override object CreateChineseIDCard(IdentityProperty idProperty)
29: {
30: // TODO: Invoke the special method to create an Chinese ID card.
31:
32: return new object();
33: }
34:
35: public override object CreateFrenchIDCard(IdentityProperty idProperty)
36: {
37: // TODO: Invoke the special method to create an French ID card.
38:
39: return new object();
40: }
41: }
42:
43: public class Director
44: {
45: private static Director _instance = null;
46: public static Director Instance
47: {
48: get { return ((_instance == null) ? _instance = new Director() : _instance); }
49: }
50:
51: public bool Check(AbstractBuilder abstractBuilder, IdentityProperty idProperty)
52: {
53: object idCard = null;
54:
55: switch (idProperty.Nationality)
56: {
57: case "Amercia":
58: idCard = abstractBuilder.CreateAmericanIDCard(idProperty);
59: break;
60: case "China":
61: idCard = abstractBuilder.CreateChineseIDCard(idProperty);
62: break;
63: case "France":
64: idCard = abstractBuilder.CreateFrenchIDCard(idProperty);
65: break;
66: default:
67: break;
68: }
69:
70: return idCard != null;
71: }
72: }
73: }
我们有AbstractBuilder这样一个抽象类,它定义了创建各种身份证的接口,然后我们用IdentityBuilder类来继承这个AbstractBuilder类并实现其内部的接口,每一个创建身份证的接口都会调用专门的方法来创建所需国家的身份证,并且这种方式把具体的实现逻辑与用户隔离开了。然后我们还有个Director类,大家可以把它想像成情报部门的一台处理身份证的机器,它可以调用外部接口来创建所需的身份证然后并对该身份证进行检测,因为检测的工序相对于制作来说要简单得多,所以用一台机器来检测所有的身份证也不难办到。现在,情报部门要做的就是用这个Director为伯恩创建一个可以使用的身份证:
1: IdentityBuilder builder = new IdentityBuilder();
2: IdentityProperty idProperty = new IdentityProperty { SerialNumber = "00127", Name = "Bourne", Nationality = "China" };
3:
4: if (!Director.Instance.Handle(builder, idProperty))
5: {
6: Console.WriteLine("*** Warning ***");
7: }
总结一下,在这种采用相同或相近数据来制作不同且制作过程比较复杂的对象时,我们可以考虑采用Builder(生成器)模式。