第13章 好菜每回味不同--建造者模式
13.2 炒面没放盐
“今天我就吃了两盘垃圾,其实这里面最关键的就在于我们是吃的爽还是吃的难受都要依赖于厨师。你再想想我们设计模式的原则?”
“啊,你的意思是依赖倒转原则?抽象不应该依赖细节,细节应该依赖于抽象,由于我们要吃的菜都依赖于厨师这样的细节,所以我们很被动。”
“老麦老肯他们的产品的,味道是由什么决定的?”“那是由她们的工作流程决定的......”
13.2 建造小人一
Pen p = new Pen(Color.Yellow);
Graphics gThin = pictureBox1.CreateGraphics();
gThin.DrawEllipse(p,50,20,30,30);//头
gThin.DrawRectangle(p,60,10,50);//身体
gThin.DrawLine(p,40,100);//左手
gThin.DrawLine(p,70,90,100);//右手
gThin.DrawLine(p,100,45,150);//左脚
gThin.DrawLine(p,85,150);//右脚
如果想画一个身体比较胖的小人呢?
Graphics gFat = pictureBox2.CreateGraphics();
gFat.DrawEllipse(p,30);
gFat.DrawEllipse(p,50);
gFat.DrawLine(p,100);
gFat.DrawLine(p,80,150);
注意看,新建造的小人少了一部分
流程依赖于程序员自身,显然是不稳定的,在建造过程中很有可能出现不稳定。
13.3 建造小人二
//廋人类
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,30);//头
g.DrawRectangle(p,50);//身体
g.DrawLine(p,100);//左手
g.DrawLine(p,100);//右手
g.DrawLine(p,150);//左脚
g.DrawLine(p,150);//右脚
}
}
胖人的类也是类似的。
客户端代码:
Pen p = new Pen(Color.Yellow);
Graphics gThin = pictureBox1.CreateGraphics();
PersonThinBuilder ptb = new PersonThinBuilder(gThin,p);
ptb.Build();
Graphics gFat = pictureBox2.CreateGraphics();
PersonThinBuilder pfb = new PersonThinBuilder(gFat,p);
pfb.Build();
13.4 建造者模式
“仔细分析你会发现,这里建造小人的‘过程’是稳定的,而具体建造的‘细节’是不同的,但对于用户来说,这些都不重要,需要的时候给用户建造一个就行了”。
如果你需要将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示的意图时,我们需要应用于一个设计模式,‘建造者(Builder)模式’,又叫生成器模式。
建造者模式可以将一个产品的内部表象与产品的生产过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到他们,而具体的建造的过程和细节就不需要知道了。
建造者模式(Builder),讲一个复杂对象的构建与它的表示分离,使得同样的构建过程创建不同的表示。
//建造人的抽象类
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 PersonThisBuilder : PersonBuilder
{
public PersonThisBuilder(Graphics g,Pen p) : base(g,p)
{ }
public override void BuilderHead()
{
g.DrawEllipse(p,30);
}
public override void BuildBody()
{
g.DrawRectangle(p,50);
}
public override void BuildArmLeft()
{
g.DrawLine(p,100);
}
public override void BuildArmRight()
{
g.DrawLine(p,100);
}
public override void BuildLegLeft()
{
g.DrawLine(p,190,150);
}
public override void BuildLegRight()
{
g.DrawLine(p,150);
}
}
//胖子类也是类似代码
现在我们还缺建造者模式中一个很重要的类,指挥者(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();
}
}
PersonDirector类的目的就是根据用户的选择来一步一步建造小人,而建造的过程在指挥者这里完成了,用户就不需要知道了,而且,由于这个过程每一步都是一定要做的,那就不会让少一只手、少一条腿的问题出现了。
客户端代码:
Pen p = new Pen(Color,Yellow);
PersonThisBuilder ptb = new PersonThisBuilder(pictureBox1,CreateGraphics(),p);
PersonDirector pdThin = new PersonDirector(pub);
pdThin.CreatePerson();
PersonFatBuilder pfb = new PersonFatBuilder(pictureBox2,p);
PersonDirector pdFat = new PersonDirector(pfb);
pdFat.CreatePerson();
13.5 建造者模式解析
Builder是什么?是为创造一个Product对象的各个部件指定的抽象接口。ConcreteBuilder是什么呢?他是具体的建造者,实现Builder接口,构造和装配各个部件。Product当然就是那些具体的产品了。
Director是指挥者,它主要是用来创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化。
建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要在定义一个具体的建造者就可以了。
13.6 建造者模式基本代码
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);
}
}
}
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;
}
}
具体建造者类:ConcreteBuilder2类……
Director类--指挥者类
class Director
{
public void Construct(Builder builder)
{
builder.BuilderPartA();
builder.BuilderPartB();
}
}
//客户端代码,客户不需知道具体的建造过程。
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();
}
当创建 复杂对象的算法 应该 独立于 该对象的组成部分 以及它们的装配方式时非常使用。