设计模式--建造者模式
在软件开发的过程中,当遇到一个“复杂的对象”,该对象由好多的部分组成,各个部分的组合比较稳定或有一定的依赖次序,但各部分自身却会经常面临着变化。如何隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”,这就是所谓的建造模式。
例子:
??? 买肯德基:(Terrylee的例子)典型的儿童餐包括一个主食,一个辅食,一杯饮料和一个玩具(例如汉堡、炸鸡、可乐和玩具车)。这些在不同的儿童餐中可以是不同的,但是组合成儿童餐的过程是相同的。
??????? 客户端:顾客。想去买一套套餐(这里面包括汉堡,可乐,薯条),可以有1号和2号两种套餐供顾客选择。
??????? 指导者角色:收银员。知道顾客想要买什么样的套餐,并告诉餐馆员工去准备套餐。
?????? 建造者角色:餐馆员工。按照收银员的要求去准备具体的套餐,分别放入汉堡,可乐,薯条等。
??????? 产品角色:最后的套餐,所有的东西放在同一个盘子里面。
??? 计算工资:工资的计算一般是:底薪+奖金-税。但底薪分为一级8000、二级6000、三级4000三个等级。根据岗位不同奖金的发放也不一样,管理及日常事务处理岗位(A类)每月根据领导及同事间的评议得分计算奖金,销售岗位(B类)则根据销售额发放提成。税金则根据奖金和底薪的数额进行计算。由此看出该工资的计算方式是比较稳定的构建算法,但对工资的每一部分都会根据不同的情况产生不同的算法,如何将客户端与变化巨烈的底薪、奖金和税金计算方式分离呢,这也比较适合用建造者模式。
Builder模式的架构????
????

??? 抽象建造者(Builder):给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。
??? 具体建造者(Concrete Builder):实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建。 在建造过程完成后,提供产品的实例。
??? 指导者(Director):调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
??? 产品(Product):要创建的复杂对象。
??? 程序实现:
??? //指导者
??? class Director
??? {
??????? public void build(Builder b)
??????? {
?????????? b.BuildPartA();
??????????? b.BuildPartB();
??????? }
??? }
??? //抽象建造者
??? abstract class Builder
??? {
?????? //创建产品的第一部分
??????? public abstract void BuildPartA();
??????? //创建产品的第二部分
??????? public abstract void BuildPartB();
??? }
??? //具体建造者类
??? class ConcreteBuilder1 : Builder
??? {
??????? Product p = new Product();
??????? public override void BuildPartA()
??????? {
??????????? p.Add("Part1","Part1");
??????? }
??????? public override void BuildPartB()
??????? {
??????????? p.Add("Part2","Part2");
??????? }
?????? //返回产品对象
??????? public Product GetProduct()
??????? {
??????????? return p;
??????? }
??? }
??? //具体建造者类
??? class ConcreteBuilder2 : Builder
??? {
?????? Product p = new Product();
??????? public override void BuildPartA()
??????? {
??????????? p.Add("PartA","PartA");
??????? }
??????? public override void BuildPartB()
??????? {
??????????? p.Add("PartB", "PartB");
??????? }
??????? //返回产品对象
??????? public Product GetProduct()
??????? {
??????????? return p;
??????? }
??? }
??? //产品类
??? class Product
??? {
??????? StringDictionary sd = new StringDictionary();
??????? public void Add(string name, string value)
??????? {
??????????? sd.Add(name, value);
??????? }
??????? public void Show()
??????? {
??????????? foreach (DictionaryEntry de in sd)
??????????? {
??????????????? Console.WriteLine(de.Key+"\t"+de.Value+"\n");
??????????? }
??????? }
??? }
??? //客户程序
??? class Client
??? {
??????? public static void Main(string[] args)
??????? {
??????????? Director d = new Director();
??????????? Builder b1 = new ConcreteBuilder1();
??????????? Builder b2 = new ConcreteBuilder2();
??????????? d.build(b1);
??????????? d.build(b2);
??????????? ((ConcreteBuilder1)b1).GetProduct().Show();
??????????? ((ConcreteBuilder2)b2).GetProduct().Show();
??????? }
??? }
(车延禄)
程序举例:创建一个证件生成的程序。
??? 任何证件生成都需要两个部分组成--姓名和号码。姓名由“姓”和“名”组成,而号码则根据不同证件由不同的生成方式。如:学生证("前缀"+号码),身份证("省份"+"城市"+"出生日期"+"随机数")。
???
??? 产品类如下实现:
??????? class Certificate
??????? {
??????????? //证件名称
??????????? private string name;
?????????? //证件号码
??????????? private string cardid;
??????????? public string Name
??????????? {
??????????????? get
??????????????? {
??????????????????? return name;
??????????????? }
??????????????? set
??????????????? {
??????????????????? name = value;
??????????????? }
??????????? }
??????????? public string CardID
??????????? {
??????????????? get
??????????????? {
??????????????????? return cardid;
??????????????? }
??????????????? set
??????????????? {
??????????????????? cardid = value;
??????????????? }
??????????? }
??????????? //显示证件信息
??????????? public void show()
??????????? {
??????????????? Console.WriteLine(name + "\n" + cardid);
??????????? }
??????? }
??? 抽象建造者:
??????? interface IBuilder
??????? {
??????????? //生成姓名
??????????? void BuildName();
??????????? //生成证件号码
??????????? void BuildCardID();
??????? }
??? 具体建造者(生成学生证):
??????? class StudentBuilder : IBuilder
??????? {
??????????? //证件对象
??????????? Certificate p = new Certificate();
??????????? private string firstname; //名字
??????????? private string lastname; //姓氏
??????????? private string cardprefix;?? //学生证前缀
??????????? private string cardno; //学生证号码
??????????? public StudentBuilder(string fname, string lname, string cprefix, string cno)
??????????? {
??????????????? this.firstname = fname;
??????????????? this.lastname = lname;
??????????????? this.cardprefix = cprefix;
??????????????? this.cardno = cno;
??????????? }
??????????? //建造学生证姓名
??????????? public void BuildName()
??????????? {
??????????????? p.Name = lastname + firstname;
??????????? }
??????????? //建造学生证号码
??????????? public void BuildCardID()
??????????? {
??????????????? p.CardID = cardprefix + cardno;
??????????? }
??????????? //返回证书对象
??????????? public Certificate GetCertificate()
??????????? {
??????????????? return p;
??????????? }
??????? }???
??????
??? 具体建造者(生成身份证)
??????? class PersonBuilder : IBuilder
??????? {
??????????? //证书对象
??????????? Certificate p = new Certificate();
??????????? private string lastname; //名字
??????????? private string firstname; //姓氏
??????????? private string provno; //省份代号
??????????? private string cityno;?? //城市代号
??????????? private DateTime birthday;??? //出生日期
??????????? private string randomcode;?? //生成身份证号的后三位随机数
??????????? public PersonBuilder(string lname, string fname, string pno, string cno, DateTime birth, string randomcode)
??????????? {
??????????????? this.lastname = lname;
??????????????? this.firstname = fname;
??????????????? this.provno = pno;
??????????????? this.cityno = cno;
??????????????? this.birthday = birth;
??????????????? this.randomcode = randomcode;
??????????? }
??????????? //建造姓名对象
??????????? public void BuildName()
??????????? {
??????????????? p.Name = lastname + firstname;
??????????? }
??????????? //建造身份证号码
??????????? public void BuildCardID()
??????????? {
??????????????? string strbirth = birthday.Year.ToString() + birthday.Month.ToString() + birthday.Day.ToString();
??????????????? p.CardID = provno + cityno + strbirth + randomcode;
??????????? }
??????????? //返回证件对象
??????????? public Certificate GetCertificate()
??????????? {
??????????????? return p;
??????????? }
??????? }???????????
??? 指导者对象:
??????? class Director
??????? {
??????????? public void Build(IBuilder b)
??????????? {
??????????????? b.BuildName();
??????????????? b.BuildCardID();
??????????? }
??????? }??????
???
??? 客户端对象:????????
??????? class Client
??????? {
??????????? public static void Main()
??????????? {
??????????????? //创建指导者
??????????????? Director d = new Director();
??????????????? Console.WriteLine("请输入要创建的证书类型:(0-驾照,1-身份证)");
??????????????? string type = Console.ReadLine();
??????????????? switch (type)
??????????????? {
??????????????????? case "0":
??????????????????????? //实例化学生证具体生成器
??????????????????????? IBuilder b1 = new StudentBuilder("伯通", "周", "鲁教字:", "99999999");
??????????????????????? d.Build(b1);
??????????????????????? b1.GetCertificate().show();
??????????????????????? break;
??????????????????? case "1":
??????????????????????? //实例化身份证具体生成器
??????????????????????? IBuilder b2 = new PersonBuilder("峰", "欧阳", "3701", "01", new DateTime(1976, 11, 23), "89x");
??????????????????????? d.Build(b2);
??????????????????????? b2.GetCertificate().show();
??????????????????????? break;
??????????????????? default:
??????????????????????? break;
??????????????? }
??????????? }
??????? }???????
???
??? 每一个具体的建造者是相互独立的,完成某一类产品的组装生成,可以完成产品在组装过程中实现更精细的控制。
??? 在客户端程序中无需了解产品的构造,只需要实例化指导者对象和具体建造者对象,然后使用指导者对象来控制具体建造者的的建造过程和建造次序。
??? 在指导者对象中用来控制具体建造对象的建造过程。
??? 在具体建造者对象中用来实现产品每一部分的具体建造过程。
??? 在产品对象用来描述产品的各部件的组成。??
???
??? 建造者模式用来控制产品的建造过程,实现产品对象的组成变化与客户程序的分离,而工厂模式实现产品类型的变化与客户端程序的分离。
???
建造模式的演化:
??? 省略抽象建造者:
??????? 如果只有一个具体建造者的话,那可以省略抽象建造者。???
??????? class Director
??????? {
??????????? ConcreteBuilder b = new ConcreteBuilder();
??????????? public void build()
??????????? {
??????????????? b.BuildPartA();
??????????????? b.BuildPartB();
??????????? }
??????? }
??????
?????? 如果只有一个具体建造者,除了可以省略抽象建造者,还可以把指导者也省略,让具体建造者也承担指导者的角色。
?????? class ConcreteBuilder : Builder
??????? {
??????????? Product p = new Product();
??????????? public override void BuildPartA()
??????????? {
??????????????? p.Add("Part1","Part1");
??????????? }
??????????? public override void BuildPartB()
??????????? {
??????????????? p.Add("Part2","Part2");
??????????? }
??????????? //返回产品对象
??????????? public Product GetProduct()
??????????? {
??????????????? return p;
??????????? }
?????????? //具体建造者承担的指导者的角色功能
?????????? public void Construct()
?????????? {
??????????????? BuildPartA();
??????????????? BuildPartB();
?????????? }
??????? }
??????
?????? 一般来说在以下两种情况下应当考虑使用建造者模式:
?????? 1、被建造的对象有复杂的组成部分,每一部分的生成算法又不一样。(采用具体建造者不同的方法,实现对象不同部分的构造)
?????? 2、被建造的对象各部分有一定的组成顺序。(用Director对ConcreteBuild方法的调用次序来控制)