生成器或者建造者(Builder)模式是将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
举个例子,假设我们正在制作一款机甲类的游戏,每个机器人由六个部分组成:头部、身体、左手、右手、左腿和右腿,分为头、身、手和腿四种类型。定义如下:
public interface IHead
{
}
public interface IBody
{
}
public interface IHand
{
}
public interface ILeg
{
}
public class Robot
{
public IBody Body { get; set;}
public IHead Head { get; set;}
public IHand LeftHand { get; set;}
public IHand RightHand { get; set;}
public ILeg LeftLeg { get; set;}
public ILeg RightLeg { get; set;}
public override string ToString ()
{
return base.ToString ()
+ Body.ToString ()
+ Head.ToString ()
+ LeftHand.ToString ()
+ RightHand.ToString ()
+ LeftLeg.ToString ()
+ RightLeg.ToString ();
}
}
我们有不同的(继承自头、身、手、腿接口)部件可以组装机器人,例如:
public class RobotHead : IHead
{
}
public class RobotBody : IBody
{
}
public class RobotHand : IHand
{
}
public class RobotLeg : ILeg
{
}
public class CyclopsHead : IHead
{
}
public class SolarBody : IBody
{
}
public class RazorHand : IHand
{
}
public class LaserHand : IHand
{
}
public class WheelLeg : ILeg
{
}
public class LauncherLeg: ILeg
{
}
例如我需要一个亚当机器人,所有的部件都是最基本的,那么如何组合起来呢?(我来组成头部)
来看看生成器模式,首先创建一个生成器接口:
public interface IRobotBuilder{
Robot robot {get;}
void CreateHead();
void CreateBody();
void CreateLeftHand();
void CreateRightHand();
void CreateLeftLeg ();
void CreateRightLeg ();
}
编写亚当的生成器:
public class AdamBuilder : IRobotBuilder{
private Robot _robot = new Robot();
public Robot robot {get {return _robot;}}
public void CreateHead()
{
_robot.Head = new RobotHead ();
}
public void CreateBody()
{
_robot.Body = new RobotBody ();
}
public void CreateLeftHand()
{
_robot.LeftHand = new RobotHand ();
}
public void CreateRightHand()
{
_robot.RightHand = new RobotHand ();
}
public void CreateLeftLeg ()
{
_robot.LeftLeg = new RobotLeg ();
}
public void CreateRightLeg ()
{
_robot.RightLeg = new RobotLeg ();
}
}
或者我们需要一个独眼剃刀机器人:
public class CyclopsRazorBuilder : IRobotBuilder
{
private Robot _robot = new Robot();
public Robot robot {get {return _robot;}}
public void CreateHead()
{
_robot.Head = new CyclopsHead ();
}
public void CreateBody()
{
_robot.Body = new RobotBody ();
}
public void CreateLeftHand()
{
_robot.LeftHand = new RobotHand ();
}
public void CreateRightHand()
{
_robot.RightHand = new RazorHand ();
}
public void CreateLeftLeg ()
{
_robot.LeftLeg = new RobotLeg ();
}
public void CreateRightLeg ()
{
_robot.RightLeg = new RobotLeg ();
}
}
这样我们就可以调用这两个类来生成不同的机器人了。
但是,每次都调用六个Create方法未免太麻烦了,而且往往我们希望构建过程对用户透明,那么你需要一个Director(策划指挥者):
static public class RobotDirector
{
static public Robot Construct(IRobotBuilder rb)
{
rb.CreateHead ();
rb.CreateBody ();
rb.CreateLeftHand ();
rb.CreateRightHand ();
rb.CreateLeftLeg ();
rb.CreateRightLeg ();
return rb.robot;
}
}
使用:
Robot adam = RobotDirector.Construct (new AdamBuilder ());
或许你并不希望用户创建builder,那么可以改写成这样:
static public class TRobotDirector
{
static public Robot Construct<T>() where T: IRobotBuilder, new()
{
T rb = new T();
rb.CreateHead ();
rb.CreateBody ();
rb.CreateLeftHand ();
rb.CreateRightHand ();
rb.CreateLeftLeg ();
rb.CreateRightLeg ();
return rb.robot;
}
}
使用:
Robot cr = TRobotDirector.Construct<CyclopsRazorBuilder> ();
然而,你或许注意到了,每当我们需要一个新的机器人的时候都要新建一个生成器,当不同的部件有千千万(例如喷火的手臂、复眼头部和原子能身体)的时候,又可能会有万万亿的生成器,这样码农可能会累死
那么,就让我们扔掉所有的生成器吧,使用反射来解决这些问题:
public static class SRobotBuilder
{
static private object CreateObjectWithName(string classname)
{
Type type = Type.GetType (classname);
return Activator.CreateInstance(type);
}
static private IHead CreateHead(string cn)
{
return (IHead)CreateObjectWithName (cn);
}
static private IBody CreateBody(string cn)
{
return (IBody)CreateObjectWithName (cn);
}
static private IHand CreateLeftHand(string cn)
{
return (IHand)CreateObjectWithName (cn);
}
static private IHand CreateRightHand(string cn)
{
return (IHand)CreateObjectWithName (cn);
}
static private ILeg CreateLeftLeg (string cn)
{
return (ILeg)CreateObjectWithName (cn);
}
static private ILeg CreateRightLeg (string cn)
{
return (ILeg)CreateObjectWithName (cn);
}
public enum RobotKey
{
Head,
Body,
LeftHand,
RightHand,
LeftLeg,
RightLeg,
}
static public Robot Construct(Dictionary<RobotKey, string> robotDict)
{
Robot robot = new Robot ();
robot.Head = CreateHead (robotDict [RobotKey.Head]);
robot.Body = CreateBody (robotDict [RobotKey.Body]);
robot.LeftHand = CreateLeftHand (robotDict [RobotKey.LeftHand]);
robot.RightHand = CreateRightHand (robotDict [RobotKey.RightHand]);
robot.LeftLeg = CreateLeftLeg (robotDict [RobotKey.LeftLeg]);
robot.RightLeg = CreateRightLeg (robotDict [RobotKey.RightLeg]);
return robot;
}
}
使用:
Dictionary<SRobotBuilder.RobotKey,string> robotDict = new Dictionary<SRobotBuilder.RobotKey, string> ();
robotDict[SRobotBuilder.RobotKey.Head] = "CyclopsHead";
robotDict[SRobotBuilder.RobotKey.Body] = "SolarBody";
robotDict[SRobotBuilder.RobotKey.LeftHand] = "RazorHand";
robotDict[SRobotBuilder.RobotKey.RightHand] = "LaserHand";
robotDict[SRobotBuilder.RobotKey.LeftLeg] = "WheelLeg";
robotDict[SRobotBuilder.RobotKey.RightLeg] = "LauncherLeg";
Robot nb = SRobotBuilder.Construct (robotDict);
这样我们就可以使用配置文件来生成默认的机器人,而且可以通过运行时生成Dictionary来动态的创建机器人(例如玩家自定义的机器人)。
最后说两句:
生成器模式一般就是用来构建变形金刚用的,如果非要抽象来讲,那么还是变形金刚,就是某个类型由不同的部分组成,而这些部分可以独立变化成不同的子类(例如创建迷宫或者组装赛车,再或者孢子)。