Posts 构造模式 Builder - 通过Director来调度指定Builder的一组方法
Post
Cancel

构造模式 Builder - 通过Director来调度指定Builder的一组方法

Builder 模式和抽象工厂模式非常相像。区别在于:

  • 抽象工厂模式: 抽象工厂模式要实现的功能是: 让消费者指定具体工厂,交给Client调用抽象工厂的接口方法,将一组多个抽象的零件组合成一个抽象的产品。

  • 构造模式 让消费者指定具体工厂,交给监督者Director调用抽象工厂的部分或全部接口,将部分或者全部零件(或者不同的过程)组装成一个抽象产品,并直接返回给消费者。

例子

比如银行要为客户制作借记卡或者信用卡,银行指定这个卡的builder,向银监局申请监理服务,银监局负责调度builder的各个方法完成生产,最后builder直接向银行返回卡产品。

角色定义:

Builder: 只负责接口定义,这个例子里是ICardBuilder,接口类似:生产空白卡片,卡片上打印姓名和卡号,最后一步是设置消费额度和年费。最终生成一个产品 ICard。

ConcreteBuilder: 具体的实现类: CreditCardBuilder或者DebigCardBuilder,

Director: 负责指导Builder的构造card的过程,在调用DebigCardBuilder的时候,可以不必调用“设置消费额度”。

ICard产品和具体实现

1
2
3
4
5
6
7
8
    interface ICard
    {
        string Name { get; set; }
        string CardType { get; set; }
        int Limit { get; set; }
        int AnnualCharge { get; set; }
        string CardDetail { get; }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
    class CreditCard : ICard
    {
        public string Name { get; set; }
        public CreditCard(string name)
        {
            Name = name;
        }
        public string CardType { get; set; }
        public int Limit { get; set; }
        public int AnnualCharge { get; set; }
        public string CardDetail { get => $"Card: {nameof(CreditCard)}, Limit: {Limit}, Charge: {AnnualCharge}"; }

    }
1
2
3
4
5
6
7
8
9
10
11
12
    class DebitCard : ICard
    {
        public string Name { get; set; }
        public DebitCard(string name)
        {
            Name = name;
        }
        public string CardType { get; set; }
        public int Limit { get; set; }
        public int AnnualCharge { get; set; }
        public string CardDetail { get => $"Card: {nameof(DebitCard)}, Limit: {Limit}, Charge: {AnnualCharge}"; }
    }

ICardBuilder和实现

ICard产品是在这里完成的。

1
2
3
4
5
6
7
8
9
    interface ICardBuilder
    {
        public ICard Card { get; set; }   // 生成ICard产品
        public void BuildBlankCard();
        public void PrintName();
        public void PrintCardNumber();
        public void SetLimit();
        public void SetCharge();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
    class DebitCardBuilder : ICardBuilder
    {
        public ICard Card { get; set ; }
        public DebitCardBuilder(string name)
        {
            Card = new DebitCard(name);
        }
        public void BuildBlankCard()
        {
            Card.CardType = "DebitCard";
        }

        public void PrintCardNumber()
        {
            Console.WriteLine($"{Card.CardType} card number is printed");
        }

        public void PrintName()
        {
            Console.WriteLine($"{Card.Name} is printed");

        }

        public void SetCharge()
        {
            Card.AnnualCharge = 0;
        }

        public void SetLimit()
        {
            Card.Limit = -1;
        }
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
    class CreditCardBuilder : ICardBuilder
    {
        public ICard Card { get; set ; }

        public CreditCardBuilder(string name)
        {
            Card = new CreditCard(name);
            
        }
        public void BuildBlankCard()
        {
            Card.CardType = "CreditCard";
        }

        public void PrintCardNumber()
        {
            Console.WriteLine($"{Card.CardType} card number is printed");
        }

        public void PrintName()
        {
            Console.WriteLine($"{Card.Name} is printed");

        }

        public void SetCharge()
        {
            Card.AnnualCharge = 200;
        }

        public void SetLimit()
        {
            Card.Limit = 20000;
        }
    }

Director类

负责调用builder的各个接口方法

1
2
3
4
5
6
7
8
9
10
11
12
    class BankDirector
    {
        public ICardBuilder Builder { get; set; }
        public void Construct()
        {
            Builder.BuildBlankCard();
            Builder.PrintCardNumber();
            Builder.PrintName();
            Builder.SetCharge();
            Builder.SetLimit();
        }
    }

如果有特殊的需求,比如不需要设置姓名的卡片,可以创建一个adhoc的方法

1
2
3
4
5
6
7
8
        public void ConstructSpecialCard()
        {
            Builder.BuildBlankCard();
            Builder.PrintCardNumber();
            //Builder.PrintName(); -- 不印上姓名
            Builder.SetCharge();
            Builder.SetLimit();
        }

这样就完成了整个模式的设计。

使用

通过Director充分使用了Builder模式。

1
2
3
4
5
6
7
	// with director
	BankDirector director = new BankDirector();
	ICardBuilder builder = new CreditCardBuilder("Jie Chen");
	director.Builder = builder;
	director.Construct();
	ICard card = builder.Card;
	System.Console.WriteLine(card.CardDetail);

如果不通过Director,也可以实现(但也失去了设计模式的意义):

1
2
3
4
5
6
7
8
	ICardBuilder builder2 = new DebitCardBuilder("Chen Jie");
	builder2.BuildBlankCard();
	builder2.PrintCardNumber();
	builder2.PrintName();
	builder2.SetCharge();
	builder2.SetLimit();
	ICard card2 = builder2.Card;
	System.Console.WriteLine(card2.CardDetail);

功能扩展

  • 添加一个新的Builder很简单,实现ICardBuilder的接口即可。
  • 自定义Builder的某个流程也很简单,只要在Director中新建一个方法,调用Builder中的一部分方法
This post is licensed under CC BY 4.0 by the author.

抽象工厂 Abstract Factory - 外部指定工厂

Singleton 单例模式 - 单例和线程安全