題目:用程式畫一個小人。 實現: 1 public partial class Form1 : Form 2 { 3 public Form1() 4 { 5 InitializeComponent(); 6 } 7 8 private void button1_Click(object sende ...
題目:用程式畫一個小人。
實現:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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類:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
主函數:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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:上面實現了將胖的小人和瘦的小人分別畫出來,但是很可能出現,如果當前需要畫的人物過多,很可能出現缺胳膊少腿的尷尬情況,考慮到人的組成部分都一致,再細緻一下代碼。
實現:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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類:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
主函數:
![](http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
註:文中所有代碼及知識點均來自於《大話設計模式》,本人屬於邊學邊看邊敲代碼邊總結的階段。