设计模式- 建造者模式
其实有很多设计模式并没有像网上一些文章那样写的很复杂,理解了一下后发现他的实现原理很清晰。比如建造者设计模式。
建造者设计模式又叫生成器模式,我们不要叫他生成器模式,我觉的这个名字不好听。我比较喜欢建造者设计模式这个名字。
先来了解一下建造者设计模式是什么?
假设你是一个帮别人组装电脑主机的人,那么可以说,这时你就是充当建造者设计模式里指挥者这么一个角色。试想一下你要怎么样帮客户组装一台主机?装主机的人一般会先确定客户需要的主机配置,例如客户要求主板用华硕的,内存用金斯顿的,硬盘用西部数据的,CPU用因特尔的,电源用航嘉的,机箱用长城的……,先确定好后,再进行组装主机。
作为装主机的人(指挥者),你根据客户提供的配置去装主机。但装主机时,先装主板还是先装硬盘,完全由你决定。具体装的过程,内部实现细节,客户不必去关心。对于客户而言他们只是需要提供他们所需要的主机配置清单而以。
那么对于装主机的人,他是这个设计模式里唯一的,不变的部份,所有的客户都是找他装,所以在C#里可以把装主机的人写成一个单独的类,他的工作就是接收不同客户传递过来给他配置清单进行组装主机。
而变化的部份是不同的主机配置清单,那么我们可以变化的这部份写一个抽象类,例如如下代码:
public abstract class ComputerBuilder { public abstract void MainBoard();//主板 public abstract void CPU();//CPU public abstract void Memory();//内存 public abstract void HardDisk();//硬盘 public abstract void PowerSupply();//电源 }
接着由不同的客户实现不同的抽象类:
//客户A需要实现的主机配置 public class CustomerA : ComputerBuilder { public override void CPU() { Console.WriteLine("AMD2代"); } public override void MainBoard() { Console.WriteLine("华硕M4N68T-MLE"); } public override void HardDisk() { Console.WriteLine("西部数据500G"); } public override void Memory() { Console.WriteLine("金斯顿2G"); } public override void PowerSupply() { Console.WriteLine("技展450w "); } } //客户B需要实现的主机配置 public class CustomerB : ComputerBuilder { public override void CPU() { Console.WriteLine("AMD Athlon64 X2 3800+ AM2"); } public override void MainBoard() { Console.WriteLine("华硕 M2V"); } public override void HardDisk() { Console.WriteLine("希捷 160G"); } public override void Memory() { Console.WriteLine("威刚VDATA 1GB DDRII667"); } public override void PowerSupply() { Console.WriteLine("Tt XP355(W3006)"); } }
从这个例子我们看出在建造者设计模式有哪些东西,有要抽象实现的方法(也就是装主机的人需要的配置,一个一个的配置可以当作一个一个的方法)。和一个建设者类(也就是装主机的人),里面有一个指挥者方法(Director)。
那么建造者设计模式可以应用在哪些场合?
在《大话设计模式》里面是这么说的:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示意图。这时候就用到了建造者模式。
读这句话的时候,我也不知道他在讲什么。但是看了里面给的代码,把思路搞清楚后再回过头来看这句,就看懂了。
还是以上面的组装电脑主机的例子来解释一下《大话设计模式》里的这句话。组装电脑的人,他组装电脑先后顺序已经做习惯了,这个过程不会改后,而且组装电脑需要的东西主板、内存、硬盘、CPU、电源这些是不会变的,但是他们的所需要的型号或者大小会变,例如客户不是要1G的金斯顿内存,他要2G的金斯顿内存,客户可能不要250G大小的西部数据硬盘,他要500G的三星硬盘。这些可都是会变化的。所以大话设计模式里的这句“使得同样的构建过程可以创建不同的表示意图”,意思就可以这么理解成配置的东西内存、主板、硬盘这些和组装电脑的过程这些都是确定的,可是配置的型号和大小的可能不同,例如可能是要2G的内存或者是4G的内存等等,所以我们可以根据一定的装机需求,不同的型号和大小就能组装出不同性能的主机来,也就是上面的创建不同的表示意图出来这句一个道理。
不知道这么说好不好理解!
好了,最后我们还是贴一下自己写的代码和大话设计模式那个例子的代码。另外我看了一个博客:http://www.cnblogs.com/lovecherry/ 他里面有篇 无废话C#设计模式之六:Builder。我的例子就是参看他后写的。
自己写的代码例子:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace 建造者模式_装主机 7 { 8 class Program 9 { 10 static void Main(string[] args) 11 { 12 13 ComputerDirector cd = null; 14 15 CustomerA ca = new CustomerA(); 16 cd = new ComputerDirector(ca); 17 cd.CreateComputer(); 18 19 CustomerB cb = new CustomerB(); 20 cd = new ComputerDirector(cb); 21 cd.CreateComputer(); 22 23 Console.ReadLine(); 24 } 25 } 26 27 public class ComputerDirector 28 { 29 private ComputerBuilder cb; 30 public ComputerDirector(ComputerBuilder cb) 31 { 32 this.cb = cb; 33 } 34 35 public void CreateComputer() 36 { 37 //开始装电脑,先装那个由装主机的指挥者决定 38 cb.CPU(); 39 cb.MainBoard(); 40 cb.Memory(); 41 cb.PowerSupply(); 42 cb.HardDisk(); 43 } 44 } 45 46 public abstract class ComputerBuilder 47 { 48 public abstract void MainBoard();//主板 49 public abstract void CPU();//CPU 50 public abstract void Memory();//内存 51 public abstract void HardDisk();//硬盘 52 public abstract void PowerSupply();//电源 53 } 54 55 //客户A需要实现的主机配置 56 public class CustomerA : ComputerBuilder 57 { 58 public override void CPU() 59 { 60 Console.WriteLine("AMD2代"); 61 } 62 63 public override void MainBoard() 64 { 65 Console.WriteLine("华硕M4N68T-MLE"); 66 } 67 68 public override void HardDisk() 69 { 70 Console.WriteLine("西部数据500G"); 71 } 72 73 public override void Memory() 74 { 75 Console.WriteLine("金斯顿2G"); 76 } 77 78 public override void PowerSupply() 79 { 80 Console.WriteLine("技展450w "); 81 } 82 } 83 84 //客户B需要实现的主机配置 85 public class CustomerB : ComputerBuilder 86 { 87 public override void CPU() 88 { 89 Console.WriteLine("AMD Athlon64 X2 3800+ AM2"); 90 } 91 92 public override void MainBoard() 93 { 94 Console.WriteLine("华硕 M2V"); 95 } 96 97 public override void HardDisk() 98 { 99 Console.WriteLine("希捷 160G"); 100 } 101 102 public override void Memory() 103 { 104 Console.WriteLine("威刚VDATA 1GB DDRII667"); 105 } 106 107 public override void PowerSupply() 108 { 109 Console.WriteLine("Tt XP355(W3006)"); 110 } 111 } 112 }
大话设计模式代码如下,画人的建造者模式的主要代码,写成一个PersonBuilder类:
1 namespace 建造者模式 2 { 3 //指挥者 4 class PersonDirector 5 { 6 private PersonBuilder pb; 7 public PersonDirector(PersonBuilder pb) 8 { 9 this.pb = pb; 10 } 11 12 //要画的先后顺序 13 public void CreatePerson() 14 { 15 pb.BuildHead(); 16 pb.BuildBody(); 17 pb.BuildArmLeft(); 18 pb.BuildArmRight(); 19 pb.BuildLegLeft(); 20 pb.BuildLegRight(); 21 } 22 } 23 24 //要实现的抽象方法 25 abstract class PersonBuilder 26 { 27 public abstract void BuildHead(); 28 public abstract void BuildBody(); 29 public abstract void BuildArmLeft(); 30 public abstract void BuildArmRight(); 31 public abstract void BuildLegLeft(); 32 public abstract void BuildLegRight(); 33 } 34 35 //实现抽象类,画一个瘦瘦的人 36 class PersonThinBuilder : PersonBuilder 37 { 38 private Graphics g; 39 private Pen p; 40 41 public PersonThinBuilder(Graphics g, Pen p) 42 { 43 this.g = g; 44 this.p = p; 45 } 46 47 public override void BuildHead() 48 { 49 g.DrawEllipse(p, 50, 20, 30, 30); 50 } 51 52 public override void BuildBody() 53 { 54 g.DrawRectangle(p, 60, 50, 10, 50); 55 } 56 57 public override void BuildArmLeft() 58 { 59 g.DrawLine(p, 60, 50, 40, 100); 60 } 61 62 public override void BuildArmRight() 63 { 64 g.DrawLine(p, 70, 50, 90, 100); 65 } 66 67 public override void BuildLegLeft() 68 { 69 g.DrawLine(p, 60, 100, 45, 150); 70 } 71 72 public override void BuildLegRight() 73 { 74 g.DrawLine(p, 70, 100, 85, 150); 75 } 76 } 77 78 //实现抽象类,画一个胖胖的人 79 class PersonFatBuilder : PersonBuilder 80 { 81 private Graphics g; 82 private Pen p; 83 84 public PersonFatBuilder(Graphics g, Pen p) 85 { 86 this.g = g; 87 this.p = p; 88 } 89 90 public override void BuildHead() 91 { 92 g.DrawEllipse(p, 50, 20, 30, 30); 93 } 94 95 public override void BuildBody() 96 { 97 g.DrawEllipse(p, 45, 50, 40, 50); 98 } 99 100 public override void BuildArmLeft() 101 { 102 g.DrawLine(p, 50, 50, 30, 100); 103 } 104 105 public override void BuildArmRight() 106 { 107 g.DrawLine(p, 80, 50, 100, 100); 108 } 109 110 public override void BuildLegLeft() 111 { 112 g.DrawLine(p, 60, 100, 45, 150); 113 } 114 115 public override void BuildLegRight() 116 { 117 g.DrawLine(p, 70, 100, 85, 150); 118 } 119 } 120 }
WinForm里面的代码:
1 private void button1_Click(object sender, EventArgs e) 2 { 3 //画笔 4 Pen p = new Pen(Color.Red); 5 6 //画一个瘦人 7 PersonThinBuilder ptb = new PersonThinBuilder(pictureBox1.CreateGraphics(), p); 8 //将要准备好的画瘦人的"材料"传给指挥者,由指挥者画 9 PersonDirector pdThin = new PersonDirector(ptb); 10 pdThin.CreatePerson(); 11 12 13 //同理准备好一个胖人的"材料",让指挥者画 14 PersonFatBuilder pfb = new PersonFatBuilder(pictureBox2.CreateGraphics(), p); 15 PersonDirector pdFat = new PersonDirector(pfb); 16 pdFat.CreatePerson(); 17 18 }