建造者模式--将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
麦当劳、肯德基比中式快餐成功的原因?
麦当劳、肯德基的汉堡,不管在哪家店里吃,什么时间去吃,至少在中国,味道基本都是一样的。而我们国家,比如“鱼香肉丝”,几乎所有大小中饭店都有的一道菜,但却可以吃出上万中口味来。
这是因为厨师不同,他们学习厨艺方法不同,有的人是科班出身,有人是师傅带徒弟,有人是照书下料,还有人是自我原创。不仅如此,同一个厨师,不同时间烧出来的菜也不一样,盐多盐少,炒的火候时间都是不一样的。
麦当劳、肯德基制定了非常规范的工作流程,原料放多少,加热几分钟,都有严格规定,放多少盐都是用克来衡量的。而这个工作流程是在所有的门店都必须要遵照执行的,所以我们吃到的东西不管在哪在什么时候未到都一样。这里我们吃到的食物都依赖工作流程。
建造小人一
画一个小人,要求小人要有头、身体、两手、两脚:
Pen p = new Pen (Color.Red);
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);
在画胖人的时候我们少画了一条腿。
这里我们发现,建造小人的"过程"是稳定的,都需要头、身、手、脚,而具体建造的"细节"是不同的,有胖有瘦有高有矮。但对于用户来讲,我才不管这些,我只想告诉你,我需要一个胖小人来游戏,于是你建造一个给我就行了。
如果需要将一个复杂的对象的构建与它的表示分离,使得同样的建造过程可以创建不同的表示的意图时,我们需要应用于一个设计模式,即建造者模式,又叫生成器模式。
建造者模式可以将一个产品的内部表象与产品的生成过程分割开来,从而可以使一个建造过程生成具有不同的内部表象的产品对象。如果我们用了建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需要知道了。
怎么使用建造者模式?
思考画一个小人,都需要画什么?--头、身体、左手、右手、左脚、右脚。因此,我们先 定义一个抽象的建造人的类,来把这个过程稳住,不让任何人遗忘当中的任何一步。
abstract class PersonBuilder
{
protected Graphics g;
protected Pen p;
public PersonBuilder(Graphics g, Pen p)
{
this.g = g;
this.p = p;
}
public abstract void BuilderHead();
public abstract void BuilderBody();
public abstract void BuilderArmLeft();
public abstract void BuilderArmRight();
public abstract void BuilderLegLeft();
public abstract void BuilderLegRight();
}
然后,我们需要建造一个瘦的小人,则让这个瘦子类去继承这个抽象类,那就必须去重写这些抽象方法了。否则编译器也不让你通过。
class PersonThinBuilder : PersonBuilder
{
public PersonThinBuilder(Graphics g, Pen p)
: base(g, p)
{
}
public override void BuilderHead()
{
g.DrawEllipse(p, 50, 20, 30, 30); //头
}
public override void BuilderBody()
{
g.DrawRectangle(p, 60, 50, 10, 50); //身体
}
public override void BuilderArmLeft()
{
g.DrawLine(p, 60, 50, 40, 100); //左手
}
public override void BuilderArmRight()
{
g.DrawLine(p, 70, 50, 90, 100); //右手
}
public override void BuilderLegLeft()
{
g.DrawLine(p, 60, 100, 45, 150); //左脚
}
public override void BuilderLegRight()
{
g.DrawLine(p, 70, 100, 85, 150); //右脚
}
}
同理,胖个子的用类似的代码去实现。但到目前为止,在客户端调用时,还是需要知道头身手脚这些方法,没有解决问题。因此与引入建造者模式中一个很重要的类指挥者(Director),用它来控制建造过程,也用它来隔离用户与建造过程的关联。
class PersonDirector
{
private PersonBuilder pb;
public PersonDirector(PersonBuilder pb)
{
this.pb = pb;
}
public void createPerson()
{
pb.BuilderHead();
pb.BuilderBody();
pb.BuilderArmLeft();
pb.BuilderArmRight();
pb.BuilderLegLeft();
pb.BuilderLegRight();
}
}
因此,客户端的代码可以这么写,如:
Pen p = new Pen (Color.Red);
Graphics gThin = pictureBox1.CreateGraphics();
PersonThinBuilder ptb = new PersonThinBuilder(gThin, p);
PersonDirector pdThin = new PersonDirector(ptb);
pdThin.createPerson();
Graphics gFat = pictureBox2.CreateGraphics();
PersonFatBuilder pfb = new PersonFatBuilder(gFat, p);
PersonDirector pdFat = new PersonDirector(pfb);
pdFat.createPerson();