建造者模式Builder在书中用来对于角色的组装,角色组装可以使用工厂模式来生存角色对象,但是如果要对
角色(双方士兵)作不同差异功能的时候就要再次分开写两个新的工厂类(我方士兵工厂类,敌方士兵工厂类),如果要对士兵类添加新的功能,则可以往工厂类添加方法。
但是这样做会让工厂管理类
这时可以用到建造者模式了
GOF对建造者模式的定义是:
将一个复杂对象的构建流程与它的对象表现分离出来,让相同的构建流程可以产生出不同的对象行为的表现
比如说,配置一辆车子时,都会按照一定的步骤来组装
准备车架-> 外观烤漆 -> 将引擎放入车架 -> 装入内装椅
此时就把组装的流程定义好了,但是具体的需求完全可以由我们来设定
建造者模式可以分两个步骤来实施
1、将赋值的构建流程独立出来,并将整个流程分成几个步骤,其中的每一个步骤可以是一个功能组件的设置,也可以是参数的指定,并且在一个构造方法中,将这些步骤串接起来
2、定义一个专门实现这些步骤(提供这些功能)的实现者,这些实现者知道每一部分该如何完成,并且能接受参数来决定要产出的功能,但不知道整个组装的流程是什么。
流程分析安排,功能分开实现,就能让建造者模式应用在复杂的对象构建流程上。
此时我们需要知道一些术语:
1、Director(建造指示者)
负责对象构建时的流程安排
该类有一个方法,明确定义对象组装的流程,即调用Builder接口方法的顺序
2、Builder( 功能实现接口 )
定义不同的操作方法将“功能分开来实现”
其中每一个方法都是用来提供给某复杂对象的一部分功能,或是提供设置规则
3、ConcreteBuilder( 功能实现者 )
Builder的具体实现,实现产出功能的类。
不同的功能实现者可以产出不同的功能,用来实现不同对象的行为表现功能
4、Product产品
代表最终完成的复杂对象,必须提供方法让Builder类可以将各部分功能设置给它
public class Director{
private Product m_product;
public Director(){}
//构建方法
public void Construct(Builder theBulider) {
m_product = new Product();
theBulider.BuilderPart1(m_product);
theBulider.BuilderPart2(m_product);
}
public void Product GetProduct(){
return m_product;
}
}
//建造者接口,确定实现大致功能
public abstruct class Bulider{
public void abstruct void BuilderPart1(Product theProduct);
public void abstruct void BuilderPart2(Product theProduct);
}
//子类来实现接口所需的方法,不同的子类可以定义不同属性的功能
//产出的功能直接传入给theProduct对象
public class ConcreateBuilderA : Builder {
public override void BuildPart1(Product theProduct) {
theProduct.AddPart("ConcreateBuilderA_part1");
}
public override void BuildPart2(Product theProduct) {
theProduct.AddPart("ConcreateBuilderA_part2");
}
}
public class ConcreateBuilderB : Builder {
public override void BuildPart1(Product theProduct) {
theProduct.AddPart("ConcreateBuilderB_part1");
}
public override void BuildPart2(Product theProduct) {
theProduct.AddPart("ConcreateBuilderB_part2");
}
}
public class Product{
// 产品类就需要对数据进行封装,写一些公有Set方法,让Builder的方法来为Product类设置属性字段对象
private List m_Part = new List();
public Product(){}
public void AddPart(string part){
m.Part.Add(part);
}
public void ShowProduct(){
foreach(string part in m_Part){
Debug.Log(Part);
}
}
}
//获取流程
void UnitTest(){
Director theDirector = new Director();
Product theProduct = null;
//使用BuilderA构造
theDirector.Construct(new ConCreateBuilderA());
theProduct = theDirector.GetResult();
theProduct.ShowProduct();
theDirector.Construct(new ConCreateBuilderB());
theProduct = theDirector.GetResult();
theProduct.ShowProduct();
}
在Director建造指示者的指挥下,将不同属性的功能指定给Product,最后获取Product。
可以看到,Product对象在使用不同的Builder(功能实现者)时,会有不同的功能表现。
按照建造者模式的两个原则:流程分析安排,和功能分开实现
从原先的实现中可以发行有一些是可以有固定的流程的
如给角色对象添加功能的流程方法
AddCharacterFuncs() {
设置显示模式
AddGameObject()
设置武器
AddWaePon()
设置角色属性
AddAttr()
设置角色AI
AddAI()
}
上述就是有固定的流程安排
而Solider 角色工厂(SoldierFactory) 和 Enemy 敌人工厂(EnemeyFactory)两个工厂方法则是功能分开实,现此时就将建造者模式找到;
但是如果在工厂上实现,则会出现前言所说的情况,增加工厂类就需要对(士兵和敌方士兵)进行重新实现,出现继承绑定的情况
所以必须对这部分流程安排从角色工厂中分离,单独实现成为一个新的系统
角色建造者系统
角色建造者系继承游戏系统接口,定义一个ConStruct方法,方法传入某个Builder的对象,方法里面指定了所需要的流程。类似于上述的Director指示者类
定义抽象类接口
1、使用一个角色建造函数参数属性抽象类,里面定义了角色所需要建造的类型对象,字段属性
使用角色构造函数类是因为当一个角色有过多的属性(7 、8 个)时,此时就传入一个专门的函数参数类,会方便后续的维护和开发
2、定义一个角色建造者抽象类,里面包含了角色大致的方法。(让子类继承做具体不同的实现)
具体实现
此时我们需要具体实现一个角色建造参数类,还可以添加上一些参数类进行扩展
如给士兵
public class SoldierBuildParam:ICharacterBuildParam {
public int LV = 0; //派生类新增的属性
public SolderBuildParam();
}
public class SoldierBuilder : ICharacterBuilder{
private SoldierBuildParam m_BuilderParam = null;
public override void SetBuildParam(ICharacterBuildParam theParam) {
m_BuildParam = theParam as SoldierBuildParam;
}
//设置模型
public override void LoadAsset(int GameObjectID){
//设置角色属性模型
m_BuildParam.NewCharacter.SetGameObject(xxx);
}
//加入点击组件功能
public override void AddOnClickScript(){
//具体实现.. 设置角色属性
}
//加入AI
public override void AddAI(){
//具体实现..给m_BuildParam 设置AI
}
}
此时工厂类有一个建造指示者对象引用,来指示设置流程调用ConStrauct方法,方法参数为传入角色建造者对象(theBuilder 士兵或敌人的建造者)。
在调用ConStrauct方法之前,需要设置一个角色函数参数属性对象引用,来设置基本的参数,并且传给theBuilder对象;theBuilder对象拥有属性参数时,在调建造指示者的ConStrauct方法,传入有属性类对象引用的theBuilder。
对于工厂类里的另一个敌人生成工厂模式方法也一样,定义一个敌人参数属性类,并通过工厂模式方法传入的参数来设置属性;然后定义一个theEnemyBuilder建造者 获取这个敌人参数
这样重构就不需要写士兵工厂,敌人工厂这两个工厂子类进行特定实现了。只需在工厂方法上添加建造指示者类对象引用,特定的建造者类,特定的建造者属性参数类。
重构后的角色工厂:
public class CharacterFactory:IcharacterFactory{
private CharaterBuilderSystem m_BuilderDirector
= new CharacterBuilderSystem(PBaseDefenseGame.Instance);
public override ISoidier CreateSoldier(ENUM_Soldier emSoldier,ENUM_Weapon emWeapon,int Lv,Vector3 SpawnPosition){
//产生对应的Character
switch(emSoldier){
case ENUM_Soldier.Rookie:
SoldierParam.NewCharacter = new SoldierRookie();
break;
case ENUM_Soldier.Sergeant:
SoldierParam.NewCharacter = new SoldierSergeant();
break;
//...
default :
Debug.LogWarning("CreatteSoldier:无法建立");
return null;
}
if(SoldierParam.NewCharacter == null)
return null;
//设置共享参数
SoldierParam.emWeapon = emWeapon;
SoldierParam.SpawnPosition = SpawnPosition;
SoldierParam.Lv = Lv;
//产生对应的Builer及设置参数
SoldierBuilder theSoldierBuilder = new SoldierBuilder();
theSoldierBuilder.SetBuildParam(SoldierParam);
m_BuilderDiector.Construct(theSoldierBuilder);
return SoldierParam.NewCharacter as ISoldier;
}
//敌人工厂方法类似在此省略...
}
在重构后的角色工厂中,只简单负责角色的产生,而负责的功能组装工作交由新增加的角色建造者系统来完成。
运用建造者模式的角色建造者系统,将角色功能的组装流程给独立出来,并以明确的方法调用来实现,有助于代码的阅读和维护;而各个角色的功能装备人物,也交由不同的类来实现。并使用接口方法操作,降低系统之间的耦合度。当实现系统有任何变化时,也可以使用实现类的方式来应付。
建造者模式让复杂的对象的生产流程与功能实现进行拆分,让系统调用和维护变得更加容易。
此外,在不需要更新实现者的情况下,调整生产流程的顺序就能完成装备线的更改。