`
leo918
  • 浏览: 10062 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

设计模式--建造者模式

阅读更多

在软件开发的过程中,当遇到一个“复杂的对象”,该对象由好多的部分组成,各个部分的组合比较稳定或有一定的依赖次序,但各部分自身却会经常面临着变化。如何隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”,这就是所谓的建造模式。
例子:
    买肯德基 :(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方法的调用次序来控制)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics