C#学习笔记-建造者模式

题目:用程序画一个小人。

实现:

 1 public partial class Form1 : Form
 2     {
 3         public Form1()
 4         {
 5             InitializeComponent();
 6         }
 7 
 8         private void button1_Click(object sender, EventArgs e)
 9         {
10             Pen p = new Pen(Color.Yellow);
11             Graphics gThin = pictureBox1.CreateGraphics();
12 
13             gThin.DrawEllipse(p, 50, 20, 30, 30);
14             gThin.DrawRectangle(p, 60, 50, 10, 50);
15             gThin.DrawLine(p, 60, 50, 40, 100);
16             gThin.DrawLine(p, 70, 50, 90, 100);
17             gThin.DrawLine(p, 60, 100, 45, 150);
18             gThin.DrawLine(p, 70, 100, 85, 150);
19 
20             Graphics gFat = pictureBox2.CreateGraphics();
21 
22             gFat.DrawEllipse(p, 50, 20, 30, 30);
23             gFat.DrawEllipse(p, 45, 50, 40, 50);
24             gFat.DrawLine(p, 50, 50, 30, 100);
25             gFat.DrawLine(p, 80, 50, 100, 100);
26             gFat.DrawLine(p, 60, 100, 45, 150);
27             gFat.DrawLine(p, 70, 100, 85, 150);
28         }
29     }
View Code

 效果截图:

 

 

题目延伸1:将画小人的部分与界面分离开,不让界面的代码显得冗长,也为了防止其他地方调用画小人的情况出现。

解析:

直接将画小人挪到单独的类里即可

PersonBuilder类:

 1     class PersonThinBuilder
 2     {
 3         protected Graphics g;
 4         protected Pen p;
 5         public PersonThinBuilder(Graphics g,Pen p)
 6         {
 7             this.g = g;
 8             this.p = p;
 9         }
10 
11         public void Build()
12         {
13             g.DrawEllipse(p, 50, 20, 30, 30);
14             g.DrawRectangle(p, 60, 50, 10, 50);
15             g.DrawLine(p, 60, 50, 40, 100);
16             g.DrawLine(p, 70, 50, 90, 100);
17             g.DrawLine(p, 60, 100, 45, 150);
18             g.DrawLine(p, 70, 100, 85, 150);
19         }
20     }
21     class PersonFatBuilder
22     {
23         protected Graphics g;
24         protected Pen p;
25         
26         public PersonFatBuilder(Graphics g, Pen p)
27         {
28             this.g = g;
29             this.p = p;
30         }
31 
32         public void Build()
33         {
34             g.DrawEllipse(p, 50, 20, 30, 30);
35             g.DrawEllipse(p, 45, 50, 40, 50);
36             g.DrawLine(p, 50, 50, 30, 100);
37             g.DrawLine(p, 80, 50, 100, 100);
38             g.DrawLine(p, 60, 100, 45, 150);
39             g.DrawLine(p, 70, 100, 85, 150);
40         }
41     }
View Code

主函数:

 1 private void button1_Click(object sender, EventArgs e)
 2         {
 3             Pen p = new Pen(Color.Yellow);
 4             Graphics gThin = pictureBox1.CreateGraphics();
 5             PersonThinBuilder ptb = new PersonThinBuilder(gThin, p);
 6             ptb.Build();
 7 
 8             Graphics gFat = pictureBox2.CreateGraphics();
 9             PersonFatBuilder pfb = new PersonFatBuilder(gFat, p);
10             pfb.Build();
11         }
View Code

 

 

题目延伸2:上面实现了将胖的小人和瘦的小人分别画出来,但是很可能出现,如果当前需要画的人物过多,很可能出现缺胳膊少腿的尴尬情况,考虑到人的组成部分都一致,再细致一下代码。

实现:

  1     abstract  class PersonBuilder
  2     {
  3         protected Graphics g;
  4         protected Pen p;
  5 
  6         public PersonBuilder(Graphics g,Pen p)
  7         {
  8             this.p = p;
  9             this.g = g;
 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     }
 19     /// <summary>
 20     /// 继承于PersonBuilder类
 21     /// 必须全部重写PersonBuilder类里的抽象方法
 22     /// 这样保证了在画图的时候不会出现“缺胳膊少腿”的现象
 23     /// </summary>
 24     class PersonThinBuilder : PersonBuilder
 25     {
 26         public PersonThinBuilder(Graphics g, Pen p) : base(g, p)
 27         {
 28         }
 29 
 30         public override void BuildHead()
 31         {
 32             g.DrawEllipse(p, 50, 20, 30, 30);
 33         }
 34         public override void BuildBody()
 35         {
 36             g.DrawRectangle(p, 60, 50, 10, 50);
 37         }
 38         public override void BuildArmLeft()
 39         {
 40             g.DrawLine(p, 60, 50, 40, 100);
 41         }
 42         public override void BuildArmRight()
 43         {
 44             g.DrawLine(p, 70, 50, 90, 100);
 45         }
 46         public override void BuildLegLeft()
 47         {
 48             g.DrawLine(p, 60, 100, 45, 150);
 49         }
 50         public override void BuildLegRight()
 51         {
 52             g.DrawLine(p, 70, 100, 85, 150);
 53         }
 54     }
 55     class PersonFatBuilder : PersonBuilder
 56     {
 57         public PersonFatBuilder(Graphics g, Pen p) : base(g, p)
 58         { }
 59 
 60         public override void BuildHead()
 61         {
 62             g.DrawEllipse(p, 50, 20, 30, 30);
 63         }
 64         public override void BuildBody()
 65         {
 66             g.DrawEllipse(p, 45, 50, 40, 50);
 67         }
 68         public override void BuildArmLeft()
 69         {
 70             g.DrawLine(p, 50, 50, 30, 100);
 71         }
 72         public override void BuildArmRight()
 73         {
 74             g.DrawLine(p, 80, 50, 100, 100);
 75         }
 76         public override void BuildLegLeft()
 77         {
 78             g.DrawLine(p, 60, 100, 45, 150);
 79         }
 80         public override void BuildLegRight()
 81         {
 82             g.DrawLine(p, 70, 100, 85, 150);
 83         }
 84     }
 85     /// <summary>
 86     /// 客户端调用的时候是不需要知道头身手脚这些方法的
 87     /// 所以我们需要一个很重要的类,指挥者(Director)
 88     /// 用它来控制建造过程,也隔离开了用户与建造过程的关联
 89     /// </summary>
 90     class PersonDirector
 91     {
 92         private PersonBuilder pb;
 93         public PersonDirector(PersonBuilder pb)
 94         {
 95             this.pb = pb;
 96         }
 97         public void CreatePerson()
 98         {
 99             pb.BuildHead();
100             pb.BuildBody();
101             pb.BuildArmLeft();
102             pb.BuildArmRight();
103             pb.BuildLegLeft();
104             pb.BuildLegRight();
105         }
106     }
View Code

解析:

这里用到的就是建造者模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

它主要是用于创建一些复杂的对象,这些对象的内部构建间的建造顺序通常是稳定的,蛋对象内部的构建通常面临着复杂的变化。

建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要定义一个具体的建造者就可以了。

 

 

附:再次简化主函数部分

实现:

PersonBuilder类:

  1     abstract class PersonBuilder
  2     {
  3         protected Graphics g;
  4         protected Pen p;
  5 
  6         public PersonBuilder(Graphics g, Pen p)
  7         {
  8             this.g = g;
  9             this.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     }
 19 
 20     class PersonThinBuilder : PersonBuilder
 21     {
 22         public PersonThinBuilder(Graphics g, Pen p)
 23             : base(g, p)
 24         { }
 25 
 26         public override void BuildHead()
 27         {
 28             g.DrawEllipse(p, 50, 20, 30, 30);
 29         }
 30 
 31         public override void BuildBody()
 32         {
 33             g.DrawRectangle(p, 60, 50, 10, 50);
 34         }
 35 
 36         public override void BuildArmLeft()
 37         {
 38             g.DrawLine(p, 60, 50, 40, 100);
 39         }
 40 
 41         public override void BuildArmRight()
 42         {
 43             g.DrawLine(p, 70, 50, 90, 100);
 44         }
 45 
 46         public override void BuildLegLeft()
 47         {
 48             g.DrawLine(p, 60, 100, 45, 150);
 49         }
 50 
 51         public override void BuildLegRight()
 52         {
 53             g.DrawLine(p, 70, 100, 85, 150);
 54         }
 55     }
 56 
 57     class PersonFatBuilder : PersonBuilder
 58     {
 59         public PersonFatBuilder(Graphics g, Pen p)
 60             : base(g, p)
 61         { }
 62 
 63         public override void BuildHead()
 64         {
 65             g.DrawEllipse(p, 50, 20, 30, 30);
 66         }
 67 
 68         public override void BuildBody()
 69         {
 70             g.DrawEllipse(p, 45, 50, 40, 50);
 71         }
 72 
 73         public override void BuildArmLeft()
 74         {
 75             g.DrawLine(p, 50, 50, 30, 100);
 76         }
 77 
 78         public override void BuildArmRight()
 79         {
 80             g.DrawLine(p, 80, 50, 100, 100);
 81         }
 82 
 83         public override void BuildLegLeft()
 84         {
 85             g.DrawLine(p, 60, 100, 45, 150);
 86         }
 87 
 88         public override void BuildLegRight()
 89         {
 90             g.DrawLine(p, 70, 100, 85, 150);
 91         }
 92     }
 93 
 94     class PersonDirector
 95     {
 96         private PersonBuilder pb;
 97         /**
 98          * Assembly=>程序集
 99          */
100         public PersonDirector(string type,Graphics g,Pen p)
101         {
102             string assemblyName = "建造者模式03";
103             object[] args = new object[2];
104             args[0] = g;
105             args[1] = p;
106 
107             //Assembly.CreateInstance 方法 (String, Boolean, BindingFlags, Binder, Object[], CultureInfo, Object[])
108             //从此程序集中查找指定的类型,并使用系统激活器创建它的实例,包括可选的区分大小写搜索并具有指定的区域性、参数和绑定及激活属性。 
109             //public object CreateInstance(string typeName, bool ignoreCase, BindingFlags bindingAttr, Binder binder, object[] args, CultureInfo culture, object[] activationAttributes)
110             this.pb = (PersonBuilder)Assembly.Load(assemblyName).CreateInstance(assemblyName + ".Person" + type + "Builder", false, BindingFlags.Default, null, args, null, null);
111             /**
112              * typeName
113              * 要查找的类型的 Type.FullName。 
114              * ignoreCase
115              * 如果为 true,则忽略类型名的大小写;否则,为 false。 
116              * bindingAttr
117              * 影响执行搜索的方式的位屏蔽。此值是 BindingFlags 中的位标志的组合。 
118              * binder
119              * 一个启用绑定、参数类型强制、成员调用以及通过反射进行 MemberInfo 对象检索的对象。如果 binder 为 空引用(在 Visual Basic 中为 Nothing),则使用默认联编程序。 
120              * args
121              * Object 类型的数组,包含要传递给构造函数的参数。此参数数组在数量、顺序和类型方面必须与要调用的构造函数的参数匹配。如果需要默认的构造函数,则 args 必须是空数组或 空引用(在 Visual Basic 中为 Nothing)。 
122              * culture
123              * 用于控制类型强制的 CultureInfo 的实例。如果这是 空引用(在 Visual Basic 中为 Nothing),则使用当前线程的 CultureInfo。(例如,这对于将表示 1000 的 String 转换为 Double 值是必需的,因为不同的区域性以不同的方式表示 1000。) 
124              * activationAttributes
125              * Object 类型的数组,包含一个或多个可以参与激活的激活属性。激活属性的一个示例是: URLAttribute
126              * 
127              * 返回值
128              * 表示此类型且匹配指定条件的 Object 的实例;如果没有找到 typeName,则为 空引用(在 Visual Basic 中为 Nothing)。
129              */
130         }
131         public void CreatePerson()
132         {
133             pb.BuildHead();
134             pb.BuildBody();
135             pb.BuildArmLeft();
136             pb.BuildArmRight();
137             pb.BuildLegLeft();
138             pb.BuildLegRight();
139         }
140     }
View Code

主函数:

 1  private void button1_Click(object sender, EventArgs e)
 2         {
 3             Pen p = new Pen(Color.Yellow);
 4             Graphics gThin = pictureBox1.CreateGraphics();
 5 
 6             PersonDirector pdThin = new PersonDirector("Thin", gThin, p);
 7             pdThin.CreatePerson();
 8 
 9             Graphics gFat = pictureBox2.CreateGraphics();
10 
11             PersonDirector pdFat = new PersonDirector("Fat", gFat, p);
12             pdFat.CreatePerson();
13         }
View Code

 

 

 

 

注:文中所有代码及知识点均来自于《大话设计模式》,本人属于边学边看边敲代码边总结的阶段。

posted @ 2017-10-10 20:43  多多陪着小五  阅读(392)  评论(0编辑  收藏  举报