1. 炒面没放盐

A: 吃了两盘垃圾。最关键的就就在于我们吃的爽不爽都要依赖于厨师。
B: 依赖倒转原则?抽象不应该依赖细节,细节应该依赖于抽象,由于我们要吃的菜都要依赖于厨师这样的细节,所有我们很被动。
B: 肯德基是有他们的工作流程决定的,所有无论在那吃是一样的。这里我们要吃的食物都依赖工作流程。不过工作流程好像还是细节呀。
A: 对,工作流程也是细节。你想如果肯德基发现鸡翅烤的有些焦,他们会调整具体的工作流程中的烧烤时间,如果新加一种汉堡,做法都相同,只是配料不相同,工作流程是不变的,只是加了一种具体的产品而已,这里的工作流程怎么样?
B: 对,这里工作流程可以是一种抽象的流程,具体放什么配料,烤多长时间等细节都依赖于这个抽象。

2. 建造小人

A: 看你能不能体会到流程的抽象。

private void button1_Click(object sender, EventArgs e)
{
    Pen p = new Pen(Color.Yellow);

    Graphics gThin = pictureBox1.CreateGraphics();
    
    gThin.DrawEllipse(p, 50, 20, 30, 30);
    gThin.DrawRectangle(p, 60, 50, 10, 50);
    gThin.DrawLine(p, 60, 50, 40, 100);
    gThin.DrawLine(p, 70, 50, 90, 100);
    gThin.DrawLine(p, 60, 100, 45, 150);
    gThin.DrawLine(p, 70, 100, 85, 150);

    Graphics gFat = pictureBox2.CreateGraphics();

    gFat.DrawEllipse(p, 50, 20, 30, 30);
    gFat.DrawEllipse(p, 45, 50, 40, 50);
    gFat.DrawLine(p, 50, 50, 30, 100);
    gFat.DrawLine(p, 80, 50, 100, 100);
    gFat.DrawLine(p, 60, 100, 45, 150);
    gFat.DrawLine(p, 70, 100, 85, 150);
}

3. 建造小人2

class PersonThinBuilder
{
    private Graphics g;
    private Pen p;

    public PersonThinBuilder(Graphics g, Pen p)
    {
        this.g = g;
        this.p = p;
    }

    public void Build()
    {
        g.DrawEllipse(p, 50, 20, 30, 30);
        g.DrawRectangle(p, 60, 50, 10, 50);
        g.DrawLine(p, 60, 50, 40, 100);
        g.DrawLine(p, 70, 50, 90, 100);
        g.DrawLine(p, 60, 100, 45, 150);
        g.DrawLine(p, 70, 100, 85, 150);
    }
}

class PersonFatBuilder
{
    private Graphics g;
    private Pen p;

    public PersonFatBuilder(Graphics g, Pen p)
    {
        this.g = g;
        this.p = p;
    }

    public void Build()
    {
        g.DrawEllipse(p, 50, 20, 30, 30);
        g.DrawEllipse(p, 45, 50, 40, 50);
        g.DrawLine(p, 50, 50, 30, 100);
        g.DrawLine(p, 80, 50, 100, 100);
        g.DrawLine(p, 60, 100, 45, 150);
        g.DrawLine(p, 70, 100, 85, 150);
    }
}

A: 确实达到了复用,但是炒面忘记放盐的问题,缺胳膊少腿的问题依然存在。
B: 是呀,最好规定,凡是建造小人,都必须要有头和身体,以及两手两脚。

4. 建造者模式

A: 建造小人是稳定的,细节是不同的,有高矮胖瘦。但用户不管这些,你给我知道的小人就可以了。如果你需要将一个复杂对象的构造与它的表示分离,使得同样的构建过程可以创建不同的表示的意图时,需要建造者模式。如果我们指定建造者模式,那么用户就只需要建造的类型就可以得到它们,而具体建造的过程和细节就不需要知道。

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

代码结构图:
图1
A:先定义一个抽象的建造人的类,来把这个过程给稳定住,不让任何人遗忘当中的任何一步。

abstract class PersonBuilder
{
    protected Graphics g;
    protected Pen p;

    public PersonBuilder(Graphics g, Pen p)
    {
        this.g = g;
        this.p = p;
    }

    public abstract void BuildHead();
    public abstract void BuildBody();
    public abstract void BuildArmLeft();
    public abstract void BuildArmRight();
    public abstract void BuildLegLeft();
    public abstract void BuildLegRight();
}

class PersonThinBuilder : PersonBuilder
{
    public PersonThinBuilder(Graphics g, Pen p)
        : base(g, p)
    { }

    public override void BuildHead()
    {
        g.DrawEllipse(p, 50, 20, 30, 30);
    }

    public override void BuildBody()
    {
        g.DrawRectangle(p, 60, 50, 10, 50);
    }

    public override void BuildArmLeft()
    {
        g.DrawLine(p, 60, 50, 40, 100);
    }

    public override void BuildArmRight()
    {
        g.DrawLine(p, 70, 50, 90, 100);
    }

    public override void BuildLegLeft()
    {
        g.DrawLine(p, 60, 100, 45, 150);
    }

    public override void BuildLegRight()
    {
        g.DrawLine(p, 70, 100, 85, 150);
    }
}

class PersonFatBuilder : PersonBuilder
{
    public PersonFatBuilder(Graphics g, Pen p)
        : base(g, p)
    { }

    public override void BuildHead()
    {
        g.DrawEllipse(p, 50, 20, 30, 30);
    }

    public override void BuildBody()
    {
        g.DrawEllipse(p, 45, 50,40, 50);
    }

    public override void BuildArmLeft()
    {
        g.DrawLine(p, 50, 50, 30, 100);
    }

    public override void BuildArmRight()
    {
        g.DrawLine(p, 80, 50, 100, 100);
    }

    public override void BuildLegLeft()
    {
        g.DrawLine(p, 60, 100, 45, 150);
    }

    public override void BuildLegRight()
    {
        g.DrawLine(p, 70, 100, 85, 150);
    }
}

A: 我们还缺建造者模式中一个很重要的类,指挥者Director,用它来控制建造过程,也用它来隔离用户与建造过程的关联。

class PersonDirector
{
    private PersonBuilder pb;
    public PersonDirector(PersonBuilder pb)
    {
        this.pb = pb;
    }

    public void CreatePerson()
    {
        pb.BuildHead();
        pb.BuildBody();
        pb.BuildArmLeft();
        pb.BuildArmRight();
        pb.BuildLegLeft();
        pb.BuildLegRight();
    }
}

客服端:

private void button1_Click(object sender, EventArgs e)
{
    Pen p = new Pen(Color.Yellow);
    PersonThinBuilder ptb = new PersonThinBuilder(pictureBox1.CreateGraphics(), p);
    PersonDirector pdThin = new PersonDirector(ptb);
    pdThin.CreatePerson();

    PersonFatBuilder pfb = new PersonFatBuilder(pictureBox2.CreateGraphics(), p);
    PersonDirector pdFat = new PersonDirector(pfb);
    pdFat.CreatePerson();

}

B: 但我有个问题,如果我需要细化一些,怎么办?
A: 这就需要权衡,如果这些细节是每个具体的小人都构建的,那就应该要加进去,反之,没有必要。其实建造者模式是逐步建造产品的,所有建造者的Builder类里的那些建造方法必须要足够普遍,以便为各种类型的具体建造者构造。

5. 建造者模式解析

图2
A: Builder是什么?
B: 是为创建一个Product对象的各个部件指定的抽象接口。
A: ConcreteBuilder是什么呢?
B: 它是具体建造者,实现Builder接口,构造和装配各个部件。Product当然就是那些产品角色了。
A: Director是什么?
B: 指挥者,它是构建一个使用Builder接口的对象。
B: 那么什么时候用建造者模式呢?
A: 它主要是用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。
B: 是不是建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组织的,所以若需要改变一个产品的内部表示,只需要在定义一个具体的建造者就可以了。

6. 建造者模式的基本代码

class Program
{
    static void Main(string[] args)
    {
        Director director = new Director();
        Builder b1 = new ConcreteBuilder1();
        Builder b2 = new ConcreteBuilder2();

        director.Construct(b1);
        Product p1 = b1.GetResult();
        p1.Show();

        director.Construct(b2);
        Product p2 = b2.GetResult();
        p2.Show();

        Console.Read();
    }
}

class Director
{
    public void Construct(Builder builder)
    {
        builder.BuildPartA();
        builder.BuildPartB();
    }
}

abstract class Builder
{
    public abstract void BuildPartA();
    public abstract void BuildPartB();
    public abstract Product GetResult();
}

class ConcreteBuilder1 : Builder
{
    private Product product = new Product();

    public override void BuildPartA()
    {
        product.Add("部件A");
    }

    public override void BuildPartB()
    {
        product.Add("部件B");
    }

    public override Product GetResult()
    {
        return product;
    }
}

class ConcreteBuilder2 : Builder
{
    private Product product = new Product();
    public override void BuildPartA()
    {
        product.Add("部件X");
    }

    public override void BuildPartB()
    {
        product.Add("部件Y");
    }

    public override Product GetResult()
    {
        return product;
    }
}

class Product
{
    IList<string> parts = new List<string>();

    public void Add(string part)
    {
        parts.Add(part);
    }

    public void Show()
    {
        Console.WriteLine("\n产品 创建 ----");
        foreach (string part in parts)
        {
            Console.WriteLine(part);
        }
    }
}

A: 建造者模式是在当创建复杂对象的算法应该独立于对象的组成部分以及它们的装配方式时适用的模式。


yuanoung
10 声望1 粉丝

« 上一篇
外观模式
下一篇 »
观察者模式

引用和评论

0 条评论