今天,我们来讲一下建造者模式。
一、案例
我们来用winform画一个小人,一个头,一个身体,两只手,两条腿。
我们一般想到的代码如下:
1 /// <summary> 2 /// 画小人 3 /// </summary> 4 /// <param name="sender"></param> 5 /// <param name="e"></param> 6 private void pictureBox1_Paint(object sender, PaintEventArgs e) 7 { 8 Graphics gThin = e.Graphics; 9 Pen p = new Pen(Color.Black, 2); 10 gThin.DrawEllipse(p, 50, 20, 30, 30); 11 gThin.DrawRectangle(p, 60, 50, 10, 50); 12 gThin.DrawLine(p, 60, 50, 40, 100); 13 gThin.DrawLine(p, 70, 50, 90, 100); 14 gThin.DrawLine(p, 60, 100, 40, 150); 15 gThin.DrawLine(p, 70, 100, 85, 150); 16 }
运行的效果:
嗯,好,下面,我们再画一个稍微胖一点的小人。
代码如下:
1 private void pictureBox2_Paint(object sender, PaintEventArgs e) 2 { 3 Graphics gThin = e.Graphics; 4 Pen p = new Pen(Color.Red, 2); 5 gThin.DrawEllipse(p, 50, 20, 30, 30); 6 gThin.DrawEllipse(p, 45, 50, 40, 50); 7 gThin.DrawLine(p, 50, 50, 30, 100); 8 gThin.DrawLine(p, 80, 50, 100, 100); 9 gThin.DrawLine(p, 60, 100, 45, 150); 10 }
运行效果如下
咦,我们好像少花了条腿哦。
哈哈,像这样粗心的情况我们经常出现
二、演绎
1、第一步演绎
1 /// <summary> 2 /// 建造瘦小人的类 3 /// </summary> 4 class PersonThinBuilder 5 { 6 private Graphics _g; 7 private Pen _p; 8 9 public PersonThinBuilder(Graphics g, Pen p) 10 { 11 this._g = g; 12 this._p = p; 13 } 14 /// <summary> 15 /// 建造小人 16 /// </summary> 17 public void Build() 18 { 19 _g.DrawEllipse(_p, 50, 20, 30, 30); 20 _g.DrawRectangle(_p, 60, 50, 10, 50); 21 _g.DrawLine(_p, 60, 50, 40, 100); 22 _g.DrawLine(_p, 70, 50, 90, 100); 23 _g.DrawLine(_p, 60, 100, 40, 150); 24 _g.DrawLine(_p, 70, 100, 85, 150); 25 } 26 }
客户端
1 private void pictureBox1_Paint(object sender, PaintEventArgs e) 2 { 3 Pen p = new Pen(Color.Black); 4 Graphics gThin = e.Graphics; 5 PersonThinBuilder ptb = new PersonThinBuilder(gThin, p); 6 ptb.Build(); 7 }
我们进行了第一步的改革,看了一下代码,将客户端的画小人的过程一直到了一个类中,客户端只需要调用这个类就可以了,但是,这仍然没有解决我们上面提到的问题,如果我们要画一个胖一点的小人,我们还需要建一个类,然后再写一遍创建过程,很难保证落下什么东西(比如:少了一只手也说不定哦)
好,那么我们到底该如何解决呢?
下面就是我们将要介绍的 建造者模式。
建造者模式:将一个对象复杂的构建,与它的表示分离,使得同样的构建,可以创建不同的表示。
如果我们使用了建造者模式,那么,用户只需要指定建造的类型就可以得到他们了,而具体的建造的细节和过程就不需要知道了。
那么,我们画小人的案例该怎样使用建造者模式呢?我们一步步来分析。
画小人,都需要画,头、身体、左手、右手、左腿、右腿。
好,下面呢,我们就先来定义一个抽象的画小人的类,将这个过程固定住,不让任何人遗忘当中的任何一步。
1 abstract class PersonBuilder 2 { 3 protected Graphics G; 4 protected Pen P; 5 6 protected PersonBuilder(Graphics g, Pen p) 7 { 8 G = g; 9 P = p; 10 } 11 12 public abstract void BuildHead(); 13 public abstract void BuildBody(); 14 public abstract void BuildArmLeft(); 15 public abstract void BuildArmRight(); 16 public abstract void BuildLegLeft(); 17 public abstract void BuildLegRight(); 18 }
然后,我们需要建造一个瘦一点的小人,我们可以让瘦一点的小人去继承这个抽象类。那么这个类就必须重写抽象类中的方法了,要不编译不通过的。所以,画小人就不会丢三落四了。
1 class PersonThinBuilder : PersonBuilder 2 { 3 public PersonThinBuilder(Graphics g, Pen p) : base(g, p) 4 { 5 } 6 7 public override void BuildHead() 8 { 9 G.DrawEllipse(P, 50, 20, 30, 30); 10 } 11 12 public override void BuildBody() 13 { 14 G.DrawRectangle(P, 60, 50, 10, 50); 15 } 16 17 public override void BuildArmLeft() 18 { 19 G.DrawLine(P, 60, 50, 40, 100); 20 } 21 22 public override void BuildArmRight() 23 { 24 G.DrawLine(P, 70, 50, 90, 100); 25 } 26 27 public override void BuildLegLeft() 28 { 29 G.DrawLine(P, 60, 100, 40, 150); 30 } 31 32 public override void BuildLegRight() 33 { 34 G.DrawLine(P, 70, 100, 85, 150); 35 } 36 }
同理,胖子小人类也用上面的方式,继承抽象类,代码差不多,就不在写了。
这样就完事了吗?如果完事了的话,那么我在客户端调用的时候,还是需要调用类里面的方法,万一哪一个方法没有调用,也就会出现丢三落四的情况了,这根本没有解决问题呀。所以,到这里,我们还没有完事呢。
建造者模式还有一个非常重要的类,指挥者类。指挥者类是用来控制建造过程的,同时它也是隔离用户与建造过程的关联的。
好,下面我们来写一个指挥者类。
1 class PersonDirector 2 { 3 private PersonBuilder pb; 4 //用户告诉指挥者,我需要什么样的小人 5 public PersonDirector(PersonBuilder pb) 6 { 7 this.pb = pb; 8 } 9 //根据用户的选择建造小人 10 public void CreatePerson() 11 { 12 pb.BuildHead(); 13 pb.BuildBody(); 14 pb.BuildArmLeft(); 15 pb.BuildArmRight(); 16 pb.BuildLegLeft(); 17 pb.BuildLegRight(); 18 } 19 }
这样,指挥者类写好了。其实指挥者类就是根据用户的选择,来一步一步的建造小人,而建造的过程在指挥者里面已经完成了,用户就不需要知道了。
那么,客户端就是这样的了。
1 private void pictureBox1_Paint(object sender, PaintEventArgs e) 2 { 3 //瘦小人 4 PersonBuilder pb = new PersonThinBuilder(e.Graphics, new Pen(Color.Black)); 5 //告诉建造者,我要创建一个瘦小人 6 PersonDirector pd = new PersonDirector(pb); 7 //开始创建 8 pd.CreatePerson(); 9 }
ok,这样就成功的将我们的案例用建造者模式构建出来了。
好了,建造者模式今天就讲到这里了,下篇博文我们将 观察者模式
本系列将持续更新,喜欢的小伙伴可以点一下关注和推荐,谢谢大家的支持。