天天看点

大话设计模式:建造者模式

一、什么是建造者模式

将建造过程与表示分离
           

建造者模式可以让相同的建造过程有不同的具体表现,把建造的流程隐藏,外界只需要告知建造对象的类型.整个建造者的组成部分有哪些是固定的,具体该如何实现这些不部分,可以不同.

UML图
           
大话设计模式:建造者模式

Build: 负责规定建造对象所需要的组成部分,使用抽象方法,缺一不.

ConcreteBuild:建造者的具体实现类,各个组成部分具体是实现什么在这里确定

Product:产品类,给ConcreteBuild类提供具体产品

Director:导演类,在这里对具体的建造者的组成部分进行组装

二、适用场景

建造者模式适用于那些具有复杂构成的对象,外界又不必关心该对象是如何组成构建的情况.比如一碗拉面,由面、汤头、臊子、佐料组成,这是必要的组成部分,可客人不需要知道你怎么做的,我就只要一碗牛肉拉面,那你就给我做好了呈上来就行。当创建对象的复杂算法独立该对象的组成部分以及装配方式时适用。

三、优缺点

优点

建造者独立易于扩展

便于控制细节风险

缺点

具体建造者必须有共同点,范围有限制

如果内部变化复杂,会有很多建造者

四、大话中的例子

画胖子和画瘦子的例子,画一个胖子需要一个头,两只手,一个身子,两条腿,画瘦子也是这样,只不过画身子的尺寸大小不一样。在抽象建造者类里面确定好 实现 头、手、 身子、腿的抽象方法, 具体的胖子或者瘦子建造者类里面那就去实现这些抽象方法,不会有遗漏,然后导演类将这些部分组合起来,形成完整的对象,供外界调用。

五、我的例子

using System;
using System.Collections.Generic;

namespace BuildMode
{
    class Program
    {
        static void Main(string[] args)
        {
            PayneSixDirector payneSixDirector = new PayneSixDirector();//实例导演
            EarlyPayneSix changmen = new EarlyPayneSix();//长门
            LaterPayneSix daitu = new LaterPayneSix();//带土
            payneSixDirector.Construt(changmen);//我要找长门的六道,具体那六道,我不管,你自己弄.
            payneSixDirector.Construt(daitu);//我要找带土的六道,具体那六道,我不管,你自己弄.
            Console.WriteLine("==========第一代佩恩六道===========");
            changmen.Result().Show();//展示组成者
            Console.WriteLine("==========第二代佩恩六道===========");
            daitu.Result().Show();
            Console.ReadKey();

        }
    }


    /// <summary>
    /// 佩恩六道抽象类
    /// </summary>
    public abstract class PayneSix
    {

        protected ConstituteMember constituteMember;//组成成员
        public PayneSix()
        {
            constituteMember = new ConstituteMember();
        }

        /// <summary>
        /// 天道
        /// </summary>
        public abstract void SetHeaven();
        /// <summary>
        /// 修罗道
        /// </summary>
        public abstract void SetShura();
        /// <summary>
        /// 人间道
        /// </summary>
        public abstract void SetEarth();
        /// <summary>
        /// 畜生道
        /// </summary>
        public abstract void SetAnimal();
        /// <summary>
        /// 饿鬼道
        /// </summary>
        public abstract void SetHungryGhost();
        /// <summary>
        /// 地狱道
        /// </summary>
        public abstract void SetHell();

        public abstract ConstituteMember Result();
    }

    /// <summary>
    /// 早期的佩恩六道
    /// </summary>
    public class EarlyPayneSix : PayneSix
    {

        public override ConstituteMember Result()
        {
            return constituteMember;
        }

        public override void SetAnimal()
        {
            constituteMember.Add(new Ninja("畜生道·风褚"));//我可以放不同的忍者,但是必须有畜生道以及其它五道.
        }

        public override void SetEarth()
        {
            constituteMember.Add(new Ninja("人间道·泷隐土刃"));//这就是固定组成部分相同,但具体实现不同
        }

        public override void SetHeaven()
        {
            constituteMember.Add(new Ninja("天道·弥彦"));
        }

        public override void SetHell()
        {
            constituteMember.Add(new Ninja("地狱道·火迪"));
        }

        public override void SetHungryGhost()
        {
            constituteMember.Add(new Ninja("饿鬼道·雷偔"));
        }

        public override void SetShura()
        {
            constituteMember.Add(new Ninja("修罗道·水宿"));
        }
    }

    /// <summary>
    /// 后期的佩恩六道
    /// </summary>
    public class LaterPayneSix : PayneSix
    {
        public override ConstituteMember Result()
        {
            return constituteMember;
        }

        public override void SetAnimal()
        {
            constituteMember.Add(new Ninja("畜生道·芙"));
        }

        public override void SetEarth()
        {
            constituteMember.Add(new Ninja("人间道·羽高"));
        }

        public override void SetHeaven()
        {
            constituteMember.Add(new Ninja("天道·由木人"));
        }

        public override void SetHell()
        {
            constituteMember.Add(new Ninja("地狱道·老紫"));
        }

        public override void SetHungryGhost()
        {
            constituteMember.Add(new Ninja("饿鬼道·矢仓"));
        }

        public override void SetShura()
        {
            constituteMember.Add(new Ninja("修罗道·樊"));
        }
    }

    public class PayneSixDirector
    {
        /// <summary>
        /// 组合建造,根据你传过来的建造者(佩恩六道)
        /// </summary>
        /// <param name="payneSix"></param>
        public void Construt(PayneSix payneSix)
        {
            payneSix.SetAnimal();
            payneSix.SetEarth();
            payneSix.SetHeaven();
            payneSix.SetHell();
            payneSix.SetHungryGhost();
            payneSix.SetShura();
        }
    }

    /// <summary>
    /// 组成成员
    /// </summary>
    public class ConstituteMember
    {
        List<Ninja> ninjasList;
        public ConstituteMember()
        {
            ninjasList = new List<Ninja>();
        }
        public void Add(Ninja ninja)
        {
            ninjasList.Add(ninja);
        }

        public void Show()
        {
            foreach (Ninja item in ninjasList)
            {
                Console.WriteLine(item.Name);
            }
        }
    }

    /// <summary>
    /// 忍者
    /// </summary>
    public class Ninja
    {
        string _name;
        public string Name { get { return _name; } set { _name = value; } }
        public Ninja(string name)
        {
            _name = name;
        }
    }

}

           
运行结果
           
大话设计模式:建造者模式

PS:起初觉得建造者模式和外观模式挺像的, 都是把低层次的接口封装到高层次的接口.都是把需要的一组方法写在一个方法里面,外界只需要调用这一个方法即可,但两者还是用差别,建造者模式是创建型,它的核心是将具有相同组成部分的流程归总起来,在一个方法里创建组成部分这些部分是规整的,一步步构造对象,如果不构造该对象是不完整的;而外观模式是一个结构型,它的核心是将一组方法放在一个方法里面,有点像委托,是不规整的,放什么方法,都可以.

用我的例子简单的说就是,建造者模式要求佩恩六道必须是六道,而外观模式并不强制要求,所以是不适用.外观模式灵活性更高.