小话设计模式(四)生成器模式

生成器或者建造者(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来动态的创建机器人(例如玩家自定义的机器人)。


最后说两句:

生成器模式一般就是用来构建变形金刚用的,如果非要抽象来讲,那么还是变形金刚,就是某个类型由不同的部分组成,而这些部分可以独立变化成不同的子类(例如创建迷宫或者组装赛车,再或者孢子)。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值