设计模式——构建者模式

 

需求

 

在抽象工厂模式中,每个具体的工厂负责创建一个系列相互关联的产品,当一系列相互关联的产品设计到一个工厂类里后,客户端的调用会变得简单;如果要更换这一系列的产品,只只要切换一个具体的工厂类即可。

 

但是,在实体工厂里包含着零件组装逻辑,这违反了工厂类的单一职责原则,使得工厂类既要负责对象的创建,又要负责零件的组装。如果把组装逻辑转移到客户端,则又会使得客户端变得臃肿。

 

如何设计一个单独的类来负责零件的组装,就可以解决则各问题,而且可以组装出不同系列,这就是构建者模式(Builder Pattern)的由来。

 

定义

 

在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法确相对稳定。如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中的“稳定构建算法”不随着需求改变而改变?这就是要说的建造者模式。

 

创建者模式就是将一个复杂对象的构建算法与它涉及产品的生产过程分离,使得同样的构建过程可以创建不同的表示,而且客户不用知道构建的细节。

 

引用下面一段比较经典的网文

 

关于对象性质的建造

 

有些情况下,一个对象会有一些重要的性质,在它们没有恰当的值之前,对象不能作为一个完整的产品使用。比如,一个电子邮件有发件人地址、收件人地址、主题、内容、附录等部分,而在最起码的收件人地址未被赋值之前,这个电子邮件不能发出。

 

有些情况下,一个对象的一些性质必须按照某个顺序赋值才有意义。在某个性质没有赋值之前,另一个性质则无法赋值。这些情况使得性质本身的建造涉及到复杂的商业逻辑。

 

这时候,此对象相当于一个有待建造的产品,而对象的这些性质相当于产品的零件,建造产品的过程就是组合零件的过程。由于组合零件的过程很复杂,因此,这些“零件”的组合过程往往被“外部化”到一个称作建造者的对象里,建造者返还给客户端的是一个全部零件都建造完毕的产品对象。

 

之所以使用“建造者”而没有用“生成器”就是因为用零件生产产品,“建造”更为合适,“创建”或“生成”不太恰当。

 

来自:http://www.cnblogs.com/feipeng/archive/2007/03/12/671932.html,FrankFei,2007年3月12日

  

 

创建者模式由4部分组成:(1)需要构建的复杂产品(Product),常常由多个零件组成;(2)抽象构建者(Abstract Builder):给出一个抽象接口,以规范产品对象的各个组成成分的建造。一般而言,此接口独立于应用程序的商业逻辑。模式中直接创建产品对象的是具体建造者(ConcreteBuilder)角色。具体建造者类必须实现这个接口所要求的方法:一个是建造方法,另一个是结果返还方法。(3)实体构建者(Concrete Builder):实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。(4)构建指导者/导演者(Director):构造一个使用抽象构建者的对象,调用具体建造者以创建产品对象,导演者并没有产品类的具体知识,真正拥有产品类的具体知识的是具体建造者对象。

 

案例

 

    class Program

    {

        static voidMain(string[] args)

        {

            // 客户程序

            Console.WriteLine("==开始构建男孩套装盒子:");

            ClothesBoxDirector boyClothesBoxDirector = new ClothesBoxDirector(new BoyClothesBox());

            boyClothesBoxDirector.AssembleClothesBox();

            Console.WriteLine("==开始构建女孩套装盒子:");

            ClothesBoxDirector girlClothesBoxDirector = new ClothesBoxDirector(new GirlClothesBox());

            girlClothesBoxDirector.AssembleClothesBox();

        }

    }

 

    // 衣服(产品)的零件:帽子、鞋子

    // 男孩衣服的零件:男孩帽子

    public class BoyCap

    {

        public void Show() { Console.WriteLine("男孩的帽子"); }

    }

    // 男孩衣服的零件:男孩靴子

    public class BoyShoes

    {

        public void Show() { Console.WriteLine("男孩的鞋子"); }

    }

    // 女孩衣服的零件:女孩帽子

    public class GirlCap

    {

        public void Show() { Console.WriteLine("女孩的帽子"); }

    }

    // 女孩衣服的零件:女孩靴子

    public class GirlShoes

    {

        public void Show() { Console.WriteLine("女孩的鞋子"); }

    }

 

    // 抽象构建者:套装盒子

    public interface IClothesBox

    {

        void SetCap();

        void SetShoes();

    }

    // 实体构建者:男孩套装盒子

    public class BoyClothesBox : IClothesBox

    {

        public void SetCap()

        {

            BoyCap cap = new BoyCap();

            cap.Show();

        }

        public void SetShoes()

        {

            BoyShoes shoes = new BoyShoes();

            shoes.Show();

        }

    }

    // 实体构建者:女孩套装盒子

    public class GirlClothesBox : IClothesBox

    {

        public void SetCap()

        {

            GirlCap cap = new GirlCap();

            cap.Show();

        }

        public void SetShoes()

        {

            GirlShoes shoes = new GirlShoes();

            shoes.Show();

        }

    }

 

    // 构建者导演:套装盒子导演

    public class ClothesBoxDirector

    {

        public ClothesBoxDirector(IClothesBox clothesBox) { this.clothesBox = clothesBox; }

 

        private IClothesBox clothesBox;

 

        public void AssembleClothesBox()

        {

            this.clothesBox.SetCap();

            this.clothesBox.SetShoes();

        }

    }

 

优缺点

 

优点:

 

解耦了组装过程和创建具体部件,客户程序既可以不再负责对象的创建,也不再负责对象的组装,而是把创建责任交给创建者类,把组装责任交给组装类,客户端只负责对象的调用,更加明确了各个类的职责。

 

缺点:

 

虽然利用创建者模式可以创建出不同类型的产品,但是如果产品之间的差异非常大,则需要编写多个创建者类才能实现,这时如果结合工厂模式更好。

 

适用场景

 

(1)需要生成的产品对象有复杂的内部结构。

(2)需要生成的产品对象的属性相互依赖,建造者模式可以强迫生成顺序。

(3)在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。

 

一些关键点

 

(1)建造者模式主要用于“分步骤构建一个复杂的对象”,在这其中“分步骤”是一个稳定的算法,而复杂对象的各个部分则经常变化。

(2)产品不一定需要抽象类,特别是由于创建对象的算法复杂而导致使用此模式的情况下或者此模式应用于产品的生成过程,其最终结果可能差异很大,不大可能提炼出一个抽象产品类。产品可以有抽象类描述时,则可以结合工厂模式来使用。

(3)创建者中的创建子部件的接口方法不是抽象方法而是空方法,不进行任何操作,具体的创建者只需要覆盖需要的方法就可以,但是这也不是绝对的,特别是类似文本转换这种情况下,缺省的方法将输入原封不动的输出是合理的缺省操作。

(4)前面我们说过的抽象工厂模式(Abtract Factory)解决“系列对象”的需求变化,Builder模式解决“对象部分”的需求变化,建造者模式常和组合模式(Composite Pattern)结合使用。

 

补充:构建着模式与抽象工厂模式结合使用的案例代码

 

    class Program

    {

        static voidMain(string[] args)

        {

            // 客户程序

            Console.WriteLine("==开始生产男孩套装:");

            ClothesFactoryDirector director1 = new ClothesFactoryDirector(new BoyClothesFactory());

            director1.AssembleClothes();

            Console.WriteLine("==开始生产女孩套装:");

            ClothesFactoryDirector director2 = new ClothesFactoryDirector(new GirlClothesFactory());

            director1.AssembleClothes();

        }

    }

 

    // 等级式的产品家族:帽子、靴子

    // 抽象产品:帽子

    public interface ICap { void Show(); }

    // 抽象产品:靴子

    public interface IShoes { void Show(); }

    // 实体产品:男孩帽子

    public class BoyCap : ICap

    {

        public void Show() { Console.WriteLine("男孩的帽子"); }

    }

    // 实体产品男孩靴子

    public class BoyShoes : IShoes

    {

        public void Show() { Console.WriteLine("男孩的鞋子"); }

    }

    // 实体产品:女孩帽子

    public class GirlCap : ICap

    {

        public void Show() { Console.WriteLine("女孩的帽子"); }

    }

    // 实体产品:女孩靴子

    public class GirlShoes : IShoes

    {

        public void Show() { Console.WriteLine("女孩的鞋子"); }

    }

 

    // 工厂等级

    // 抽象工厂:服装工厂

    public interface IClothesFactory

    {

        ICap CreateCap();

        IShoes CreateShoes();

    }

    // 实体工厂:男孩服装工厂

    public class BoyClothesFactory : IClothesFactory

    {

        public ICap CreateCap() { return new BoyCap(); }

        public IShoes CreateShoes() { return new BoyShoes(); }

    }

    // 实体工厂:女孩服装工厂

    public class GirlClothesFactory : IClothesFactory

    {

        public ICap CreateCap() { return new GirlCap(); }

        public IShoes CreateShoes() { return new GirlShoes(); }

    }

 

    // 构建指导者:服装工厂构建指导者

    public class ClothesFactoryDirector

    {

        private IClothesFactory _ClothesFactory;

 

        public ClothesFactoryDirector(IClothesFactory clothesFactory)

        {

            this._ClothesFactory = clothesFactory;

        }

 

        public void AssembleClothes()

        {

            this._ClothesFactory.CreateCap().Show();

            this._ClothesFactory.CreateShoes().Show();

        }

    }

posted on 2012-10-03 01:35  萨迦狐  阅读(205)  评论(0编辑  收藏  举报