生成器

生成器 Builder

生成器是一种对象创建型模式,旨在将一个复杂对象的构建和它的表示分离。
个人感觉的话,相比于抽象工厂,生成器就像是流水线。

适用情况

当创建对象的算法复杂,应该独立于对象的组成部分以及它的装配方式时。
当构造对象的过程需要构建不同表示的对象时。

有时候,一个对象的建造会比较复杂,特别是当它有很多个部件,每个部件又有不同的替换品(有不同的种类),各个部件的装配又要遵循某种算法。若是这个“装配算法”比较固定的话,那么使用生成器来生成对象那是再好不过了。
(组合Composite 就是这样的一类对象,因此它通常是使用生成器来生成的)

适用举例

你要买一量车,除了要选型号以外,还要决定玻璃用普通玻璃还是防弹玻璃,沙发用普通沙发还是真皮沙发,加不加装其他配件等,但“组装汽车”本质上还是一样的流程。
你要买肯打鸡套餐,套餐是饮品+汉堡+小吃,加钱还能得一个雪糕。但是饮品汉堡小吃都有不同的种类,他们最后加起来的价格也有一套算法。但是最后做出来的东西是个“套餐”是不变的。

一款游戏,他的剑支持自定义配置,剑柄和剑身要用户进行选择。当然,在程序内部,那些商店贩卖的剑也能使用该系统。(怎么又是剑)
(玩过猛汉王的话,就类似于贴皮武器幻化那种感觉)

例示代码

代码主要展示结构设计,并不一定合乎使用情理,也不一定最优。
在这里展示的构造可能比较简单,显得生成器不是那么重要,但是在实际使用中还可能涉及到武器数值,模型拼合等比较麻烦的东西。

基类

就不多说了
建造器里面封装了“为剑添加每一个部件”以及“获得造好的剑”的方法。
相当于一个个没有组合好的车间,每个步骤封装好,但具体怎么样做还不知道。
创造者掌管生成的算法,相当于把建造器中的车间组合成一条流水线。

//剑
public class Sword{/*一些代码*/}

//建造器
public class SwordBuilder
{
    
    //一些造剑部件的方法
    public virtual void Init();//初始化一下,准备造剑
    public virtual void BuildSwordHandle(){}
    public virtual void BuildSwordBody(){}
    //返回剑的方法
    public virtual Sword GetSword(){return null};
    //这个类相当于于一个接口,不能单独实例化
    //但为了让用户只重定义他们需要的部分,需要给一些缺省值
    protected SwordBulider(){};
}

//代表剑生成算法的一个东西
//将算法独立出来,使用算法时就不用考虑部件是具体怎么样生产的了
public class SwordCreater
{
    public static Sword CreateSword(SwordBuilder builder)
    {
        builder.Init();
        builder.BuildSwordHandle();
        builder.BuildSwordBody();
        return builder.GetSword();
    }
    //这里的造剑,就限定了他就那么个过程
    //如果是造车子,他就有更多的配件可以选了
}

衍生类

上面也提到,普通的建造器是不能单独实例化的,
因此可以写一个建造普通剑的类

//造普通剑的建造器
public class SampleSwordBuilder : SwordBuilder
{
    public SampleSwordBuilder(){/*初始化代码*/}
    public override void Init(){/*一些代码*/}
    public override void BuildSwordHandle(){/*一些装剑柄的代码*/}
    public override void BuildSwordBody(){/*一些装剑身的代码*/}
    public override void GetSword(){/*将造好的剑返回出去*/}
    //一些关于造剑的代码
}

还有心心念念的自定义剑

//自定剑建造器
public class CustomSwordBuilder : SwordBuilder
{
    //这一部分方法都和普通剑建造器一样,但是写起来确实是不同的
    public CustomSwordBuilder()
    {
    	m_currentHandle = "Default";
        m_currentBody = "Default";
    	//初始化代码
    }
    public override void Init(){/*一些代码*/}
    public override void BuildSwordHandle(){/*一些装剑柄的代码*/}
    public override void BuildSwordBody(){/*一些装剑身的代码*/}
    public override void GetSword(){/*将造好的剑返回出去*/}
    //一些方便用户使用的方法
    public CustomSwordBuilder(string handleType, string bodyType)
    {
        m_currentHandle = handleType;
        m_currentBody = bodyType;
        //一些代码
    }
    public void SetHandleType(string handleType)
    {
    	m_currentHandle = handleType;
    	//一些代码
    }
    public void SetBodyType(string bodyType)
    {
        m_currentBody = bodyType;
        //一些代码
    }
    //记录当前是生成什么剑
    private string m_currentHandle;
    private string m_currentBody;
    
    //一些代码
}

使用

用户的使用就非常方便了

//造一把普通剑
SampleSwordBuilder ssb = new SampleSwordBuilder();
Sword sampleSword = SwordCreater.CreateSword(ssb);

//造一把自定义剑
CustomSwordBuilder csb = new CustomSwordBuilder("Devil", "Angel");
Sword customSword = SwordCreater.CreateSword(csb);

总结

生成器的主要思想在于将组合对象的组件生成与对象生成算法分离,从而产生更加自由地生成对象的效果。
可能觉得与抽象工厂有些相像,因为都是用于生产复杂对象的设计模式。它与抽象工厂的主要区别是:
抽象工厂着重于相关联的系列对象,最后得到的不止是一个对象,而且生成的对象都是立刻返回的。
生成器着重于一步步构造一个复杂对象,最后得到得到的一般只有一个对象,生成的对象是最后一步才返回的。

当然,可以试试用生成器调用抽象工厂的方法来生成部件,再在最后组合。就可以满足“所有部件都是同一个系列”。(那我为什么不在自定义那里用同一个引索来创建呢?个人觉得设计模式这种东西还是比较灵活的,在没遇到实际的问题之前,谁都不知道这种模式有什么用。只要在遇到问题的时候能想到还有这样的一种解决方法,就很好了)

posted @ 2020-04-12 17:28  White丶纯白  阅读(222)  评论(0编辑  收藏  举报