第十一课 建造者模式

第十一课 建造者模式

       接着模板方法模式来讲建造者吧。其实开始我也有点模糊,看着建造者模式很想模板方法。为什么呢,这里引用一段李会军博客里的一段概述:

       在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定。如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?这就是要说的建造者模式。

       这里看到哦,“将对象各个部分组合起来的算法相对稳定”,这就立马让我想到了模板方法模式。这里这样处理无非就是使用模板定义固定的对象的建造流程吗。我在线给李会军同志提出了我的疑问。他的回答如下:

@王文斌
其实它们还是有区别的,建造者模式关注的是对象创建的过程,而模板方法关注的是行为!就这个例子来说,用哪种方法实现都没有问题,又或者可以结合它们来实现。另外,只要实现的优雅,也不用完全追求去符合某一个模式,那样反而有过度设计之嫌。

     

      其实回头我又仔细看了一下java与模式,里面分析了模板方法与建造者间的关系。个人感觉,其实建造者模式就是利用了模板方法,正如上面说的。建造者用的时候,是为了解决构造复杂对象。这些复杂对象往往对创建顺序等逻辑有特殊要求,但是逻辑是有共通点存在的,所以利用了模板方法的处理方式。把“创建”这一行为单独抽取出来,定义模板,这样就把共通逻辑拿出来了。但是创建者最终目的是要创建对象返回,就像李会军同志给解答的,建造者模式关注的是“对象创建”的过程。最终目的是要创建一个对象。我觉得完全可以理解为模板方法的一个特殊用法。呵呵,废话半天,来看个实例吧。(出自大话设计模式)

      (话说csdn都不让上传附件吗。。。)

      首先介绍一下,这是一个winform的程序实例,实现2个小人的绘制。

      首先是建造者实现:(我考虑先把全部代码贴出来,然后再分析,方便大家考出来运行)

1.          using System;

2.        using System.Collections.Generic;

3.        using System.Text;

4.        using System.Drawing;

5.        using System.Reflection;

6.         

7.        namespace 建造者模式

8.        {

9.            abstract class PersonBuilder

10.         {

11.             protected Graphics g;

12.             protected Pen p;

13.      

14.             public PersonBuilder(Graphics g, Pen p)

15.             {

16.                 this.g = g;

17.                 this.p = p;

18.             }

19.      

20.             public abstract void BuildHead();

21.             public abstract void BuildBody();

22.             public abstract void BuildArmLeft();

23.             public abstract void BuildArmRight();

24.             public abstract void BuildLegLeft();

25.             public abstract void BuildLegRight();

26.         }

27.      

28.         class PersonThinBuilder : PersonBuilder

29.         {

30.             public PersonThinBuilder(Graphics g, Pen p)

31.                 : base(g, p)

32.             { }

33.      

34.             public override void BuildHead()

35.             {

36.                 g.DrawEllipse(p, 50, 20, 30, 30);

37.             }

38.      

39.             public override void BuildBody()

40.             {

41.                 g.DrawRectangle(p, 60, 50, 10, 50);

42.             }

43.      

44.             public override void BuildArmLeft()

45.             {

46.                 g.DrawLine(p, 60, 50, 40, 100);

47.             }

48.      

49.             public override void BuildArmRight()

50.             {

51.                 g.DrawLine(p, 70, 50, 90, 100);

52.             }

53.      

54.             public override void BuildLegLeft()

55.             {

56.                 g.DrawLine(p, 60, 100, 45, 150);

57.             }

58.      

59.             public override void BuildLegRight()

60.             {

61.                 g.DrawLine(p, 70, 100, 85, 150);

62.             }

63.         }

64.      

65.         class PersonFatBuilder : PersonBuilder

66.         {

67.             public PersonFatBuilder(Graphics g, Pen p)

68.                 : base(g, p)

69.             { }

70.      

71.             public override void BuildHead()

72.             {

73.                 g.DrawEllipse(p, 50, 20, 30, 30);

74.             }

75.      

76.             public override void BuildBody()

77.             {

78.                 g.DrawEllipse(p, 45, 50, 40, 50);

79.             }

80.      

81.             public override void BuildArmLeft()

82.             {

83.                 g.DrawLine(p, 50, 50, 30, 100);

84.             }

85.      

86.             public override void BuildArmRight()

87.             {

88.                 g.DrawLine(p, 80, 50, 100, 100);

89.             }

90.      

91.             public override void BuildLegLeft()

92.             {

93.                 g.DrawLine(p, 60, 100, 45, 150);

94.             }

95.      

96.             public override void BuildLegRight()

97.             {

98.                 g.DrawLine(p, 70, 100, 85, 150);

99.             }

100.      }

101.   

102.      class PersonDirector

103.      {

104.          private PersonBuilder pb;

105.          public PersonDirector(string type, Graphics g, Pen p)

106.          {

107.              string assemblyName="建造者模式";

108.              object[] args = new object[2];

109.              args[0] = g;

110.              args[1] = p;

111.   

112.              this.pb = (PersonBuilder)Assembly.Load(assemblyName).CreateInstance(assemblyName+".Person" + type + "Builder"false, BindingFlags.Default, null, args, nullnull);

113.          }

114.   

115.          public void CreatePerson()

116.          {

117.              pb.BuildHead();

118.              pb.BuildBody();

119.              pb.BuildArmLeft();

120.              pb.BuildArmRight();

121.              pb.BuildLegLeft();

122.              pb.BuildLegRight();

123.          }

124.      }

125.  }

126.   

窗体代码:

1.        using System;

2.        using System.Collections.Generic;

3.        using System.ComponentModel;

4.        using System.Data;

5.        using System.Drawing;

6.        using System.Text;

7.        using System.Windows.Forms;

8.         

9.        namespace 建造者模式

10.     {

11.         public partial class Form1 : Form

12.         {

13.             public Form1()

14.             {

15.                 InitializeComponent();

16.             }

17.      

18.             private void Form1_Load(object sender, EventArgs e)

19.             {

20.             }

21.      

22.             private void button1_Click(object sender, EventArgs e)

23.             {

24.                 Pen p = new Pen(Color.Yellow);

25.                 PersonDirector pdThin = new PersonDirector("Thin",pictureBox1.CreateGraphics(),p);

26.                 pdThin.CreatePerson();

27.      

28.                 PersonDirector pdFat = new PersonDirector("Fat", pictureBox2.CreateGraphics(), p);

29.                 pdFat.CreatePerson();

30.             }

31.         }

32.     }

窗体设计代码:

1.        namespace 建造者模式

2.        {

3.            partial class Form1

4.            {

5.                /// <summary>

6.                /// 必需的设计器变量。

7.                /// </summary>

8.                private System.ComponentModel.IContainer components = null;

9.         

10.             /// <summary>

11.             /// 清理所有正在使用的资源。

12.             /// </summary>

13.             /// <param name="disposing">如果应释放托管资源,为 true;否则为 false</param>

14.             protected override void Dispose(bool disposing)

15.             {

16.                 if (disposing && (components != null))

17.                 {

18.                     components.Dispose();

19.                 }

20.                 base.Dispose(disposing);

21.             }

22.      

23.             #region Windows 窗体设计器生成的代码

24.      

25.             /// <summary>

26.             /// 设计器支持所需的方法 - 不要

27.             /// 使用代码编辑器修改此方法的内容。

28.             /// </summary>

29.             private void InitializeComponent()

30.             {

31.                 this.button1 = new System.Windows.Forms.Button();

32.                 this.pictureBox1 = new System.Windows.Forms.PictureBox();

33.                 this.pictureBox2 = new System.Windows.Forms.PictureBox();

34.                 ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();

35.                 ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();

36.                 this.SuspendLayout();

37.                 // 

38.                 // button1

39.                 // 

40.                 this.button1.Location = new System.Drawing.Point(300, 12);

41.                 this.button1.Name = "button1";

42.                 this.button1.Size = new System.Drawing.Size(75, 23);

43.                 this.button1.TabIndex = 0;

44.                 this.button1.Text = "button1";

45.                 this.button1.UseVisualStyleBackColor = true;

46.                 this.button1.Click += new System.EventHandler(this.button1_Click);

47.                 // 

48.                 // pictureBox1

49.                 // 

50.                 this.pictureBox1.BackColor = System.Drawing.Color.Black;

51.                 this.pictureBox1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;

52.                 this.pictureBox1.Location = new System.Drawing.Point(12, 12);

53.                 this.pictureBox1.Name = "pictureBox1";

54.                 this.pictureBox1.Size = new System.Drawing.Size(141, 184);

55.                 this.pictureBox1.TabIndex = 1;

56.                 this.pictureBox1.TabStop = false;

57.                 // 

58.                 // pictureBox2

59.                 // 

60.                 this.pictureBox2.BackColor = System.Drawing.Color.Black;

61.                 this.pictureBox2.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;

62.                 this.pictureBox2.Location = new System.Drawing.Point(159, 12);

63.                 this.pictureBox2.Name = "pictureBox2";

64.                 this.pictureBox2.Size = new System.Drawing.Size(135, 184);

65.                 this.pictureBox2.TabIndex = 2;

66.                 this.pictureBox2.TabStop = false;

67.                 // 

68.                 // Form1

69.                 // 

70.                 this.AutoScaleDimensions = new System.Drawing.SizeF( 6F ,  12F );

71.                 this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

72.                 this.ClientSize = new System.Drawing.Size(381, 208);

73.                 this.Controls.Add(this.pictureBox2);

74.                 this.Controls.Add(this.pictureBox1);

75.                 this.Controls.Add(this.button1);

76.                 this.Name = "Form1";

77.                 this.Text = "Form1";

78.                 this.Load += new System.EventHandler(this.Form1_Load);

79.                 ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();

80.                 ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();

81.                 this.ResumeLayout(false);

82.      

83.             }

84.      

85.             #endregion

86.      

87.             private System.Windows.Forms.Button button1;

88.             private System.Windows.Forms.PictureBox pictureBox1;

89.             private System.Windows.Forms.PictureBox pictureBox2;

90.      

91.         }

92.     }

93.      

94.      

最后程序入口:

1.        using System;

2.        using System.Collections.Generic;

3.        using System.Windows.Forms;

4.         

5.        namespace 建造者模式

6.        {

7.            static class Program

8.            {

9.                /// <summary>

10.             /// 应用程序的主入口点。

11.             /// </summary>

12.             [STAThread]

13.             static void  Main ()

14.             {

15.                 Application.EnableVisualStyles();

16.                 Application.SetCompatibleTextRenderingDefault(false);

17.                 Application.Run(new Form1());

18.             }

19.         }

20.     }

 

好了,看下效果图:

点击按钮:

 

下面开始分析这个实例。

 

其实我本来不打算用UML图说话呢,毕竟很多人不会看(别砸我),但是这里还是有必要贴一下的,偷了下懒,直接引用李会军博客上的图了。

首先大家可以看到,从左到右的四个角色。

1.       客户端

2.       指导者

3.       建造者

4.       产品

 

这就是建造者模式实现所牵扯的4个角色(当然有的时候根据需要可以合并指导者和建造者,这里描述一般实现)。

首先客户端是调用的喽,上例就是窗体了。

然后指导者起到一个管理这建筑人员的作用,产品的建造(其实就是初始化)要遵循他的要求来。

再来是建造者,工程实施人员,负责具体建造对象。

最后产品,就是要建造的对象。(要初始化的对象哦)

 

把上例套入这个图。(这里暂时不考虑客户端)

产品??好像没体现出来,呵呵,其实就是最终画出来的两个小人。谁规定产品一定要是一个类对象哦。

 

建造者 Builder:

PersonBuilder 抽象建筑者基类,定义了所有部件的建造方法。(头,身子,胳膊,腿)

ConcreteBuilder:

PersonThinBuilder

PersonFatBuilder

这两个是建筑者的具体实现类。

 

指导者 Director:

PersonDirector

这个是指导者。

 

其实大家看出来了没有,Builder的实现方法看着眼熟吗?是不是很向抽象工厂?特别是指导者的实现,就是通过反射返回具体工厂对象不是?不过是用来初始化自己的建造者对象了,没有返回罢了。

然后CreatePerson是具体的建造方法了。来看下面:

pb.BuildHead();             //建造头

              pb.BuildBody();             //建造身体

              pb.BuildArmLeft();          //建造左手

              pb.BuildArmRight();         //建造右手

              pb.BuildLegLeft();          //建造左腿

       pb.BuildLegRight();         //建造右腿

其实就是个模板方式吧。就是前面说得创建对象的复杂逻辑了。这个地方很可能对具体建造顺序有要求的。其实就本例来说,一般咱们画小人也是先画头再画手脚不是吗?

 

具体胳膊手就是简单的绘图方法,这里不提了。再来看客户端的调用。

1.        private void button1_Click(object sender, EventArgs e)

2.        {

3.              Pen p = new Pen(Color.Yellow);

4.              PersonDirector pdThin = new PersonDirector("Thin",pictureBox1.CreateGraphics(),p);

5.              pdThin.CreatePerson();

6.         

7.              PersonDirector pdFat = new PersonDirector("Fat", pictureBox2.CreateGraphics(), p);

8.              pdFat.CreatePerson();

9.         }

 

首先新建一个画笔(不要问为什么,自己google)。

然后创建指导者对象各一个(一胖一瘦,看着其实也像工厂方法吧)

然后分别调用指导者的建造方法。(其实就是模板方法来初始化哦)

然后就画出那两个小人了。

 

其实这个例子除去没有很好的体现出产品以外,算是很经典地实例了。Java与模式中还提到了JMail的用法,这里有兴趣的自己去查看一下。也是经典实例。

建造者模式与工厂模式同样都是为了创建对象的设计模式,所以实际应用中两者经常结合使用。这里可以看出来,其实设计模式没必要非要把界限划分的那么清晰。就像李会军同志教育我的一样,不要“过度设计”,呵呵,就是不要为了模式而模式。

以上

 

作者:王文斌

转载请注明出处

 

感谢李会军同志指导。(呵呵,叫同志好像有打官腔的味道哦)

 

晕,图片上传给我传到哪里去了,真不如原来的编辑器好用。那两个图大家自己运行下吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值