生成器
生成器 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);
总结
生成器的主要思想在于将组合对象的组件生成与对象生成算法分离,从而产生更加自由地生成对象的效果。
可能觉得与抽象工厂有些相像,因为都是用于生产复杂对象的设计模式。它与抽象工厂的主要区别是:
抽象工厂着重于相关联的系列对象,最后得到的不止是一个对象,而且生成的对象都是立刻返回的。
生成器着重于一步步构造一个复杂对象,最后得到得到的一般只有一个对象,生成的对象是最后一步才返回的。
当然,可以试试用生成器调用抽象工厂的方法来生成部件,再在最后组合。就可以满足“所有部件都是同一个系列”。(那我为什么不在自定义那里用同一个引索来创建呢?个人觉得设计模式这种东西还是比较灵活的,在没遇到实际的问题之前,谁都不知道这种模式有什么用。只要在遇到问题的时候能想到还有这样的一种解决方法,就很好了)