设计模式(十一)建造者模式

用程序画一个小人,这在游戏程序里非常常见。现在简单一点,要求是小人要有头、身体、两手、两脚就可以了。

第一版 

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);    //右脚

画人的时候,头身手脚是必不可少的,不管什么人物,开发时是不能少的。 

 现在的代码全写在Form1.cs的窗体里,要是需要在别的地方用这些画小人的程序怎么办?

第二版

(分离类)

class PersonThinBuilder{    // 瘦人的类
    private Graphics g;
    private Pen p;
    
    public PersonThinBuilder(Graphics g, Pen g){    // 初始化时确定画板和颜色
        this.g=g;
        this.p=p;
    }
    
    public void Build(){    // 建造小人
        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);    //右脚
    }
}

胖人的类也是相似的。然后在客户端里只需这样写就可以了:

Pen p = new Pen (Color.Yellow);

Graphics gThin = pictureBox1.CreateGraphics();
PersonThinBuilder ptb = new PersonThinBuilder(gThin,p);
ptb.Build();

Graphics gFat = pictureBox2.CreateGraphics();
PersonFatBuilder pfb = new PersonFatBuilder(gFat,p);
ptb.Build();

这样达到了可以复用这两个画小人程序的目的。但是炒面忘记放盐的问题依然没有解决。比如我现在需要你加一个高个的小人,你会不会因为编程不注意,又让他缺胳膊少腿呢?

其实,最好的办法,是规定凡是建造小人,都必须要有头和身体,以及两手两脚。

建造者模式

如果需要将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示时,可以应用“建造者模式”,又叫生成器模式。建造者模式可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需知道了

那么,怎么应用建造者模式呢?

首先,我们定义一个抽象的建造人的类,来把这个过程给稳定住,不让任何人遗忘当中的任何一步:

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(){
        gThin.DrawEllipse(p,50,20,30,30);    // 头
    }
    public override void BuildBody(){
        gThin.DrawRectangle(p,60,50,10,50);  // 身体
    }
    public override void BuildArmLeft(){
        gThin.DrawLine(p,60,50,40,100);    //左手
    }
    public override void BuildArmRight(){
        gThin.DrawLine(p,70,50,90,100);    //右手
    }
    public override void BuildLegLeft(){
        gThin.DrawLine(p,60,100,45,150);    //左脚
    }
    public override void BuildLegRight(){
        gThin.DrawLine(p,70,100,85,150);    //右脚
    }
}

胖人类似。

用指挥者(Director)来控制建造过程,也用它来隔离用户与建造过程的关联。

class PersonDirector{
    private PersonBuilder pb;
    // 用户告诉指挥者需要什么样的小人
    public PerDirector(PersonBuilder pb){
        this.pb=pb;
    }
    public void CreatePerson(){
        // 根据用户的选择建造小人
        pb.BuildHead();
        pb.BuildBody();
        pb.BuildArmLeft();
        pb.BuildArmRight();
        pb.BuildLegLeft();
        pb.BuildLegRight();
    }
}

PersonDirector类的目的就是根据用户的选择来一步一步建造小人,而建造的过程在指挥者这里完成了,用户就不需要知道了。而且,由于这个过程每一步都是一定要做的,那就不会让少画了一只手、少画一条腿的问题出现了。

 代码结构图:

客户端代码:

Pen p = new Pen(Color.Yellow);
PersonThinBuilder ptb = new PersonThinBuilder(pictureBox1.CreateGraphics(),p);
PersonDirector pdThin = new PersonDirector(ptb);
pdThin.CreatePerson();

PersonFatBuilder ptb = new PersonFatBuilder(pictureBox1.CreateGraphics(),p);
PersonDirector pdFat = new PersonDirector(ptb);
pdFat.CreatePerson();

建造者模式

建造者模式主要用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。

Product类——产品类,由多个部件组成。

class Product{
    IList<string> parts = new List<string>();
    public void Add(string part){     // 增加产品部件
        patrs.Add(part);
    }

    public void Show(){
        Console.WriteLine("\n产品 创建 ----");
        // 列举所有的产品部件
        foreach (string part in parts){
            Console.WriteLine(part);
        }
    }

}

Builder类——抽象建造者类,确定产品由两个部件PartA和PartB组成,并声明一个得到产品建造后结果的方法GetResult。

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

 ConcreteBuilder1类——具体建造者类。

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;
    }
}

Director类——指挥者类。

class Director {
    public void Construct(Builder builder){
        // 用来指挥建造过程
        builder.BuildPartA();
        builder.BuildPartB();
    }
}

客户端代码:

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

    // 指挥者用ConcreteBuilder1的方法来建造产品
    director.Construct(b1);
    Product p1= b1.GetResult();
    p1.Show();

    // 指挥者用ConcreteBuilder2的方法来建造产品    
    director.Construct(b2);
    Product p2= b2.GetResult();
    p2.Show();

    Console.Read();
}

总结:

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

 本章完。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 本文是连载文章,此为第十一章,学习将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示的建造者模式。

上一章:https://blog.csdn.net/qq_36770641/article/details/82817366  外观模式

下一章:https://blog.csdn.net/qq_36770641/article/details/82833027  观察者模式

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------    

猜你喜欢

转载自blog.csdn.net/qq_36770641/article/details/82818444