小话设计模式(二)工厂方法模式

工厂方法(Factory Method)由名虚构造器(Virtual Constructor),是一种创建型的设计模式。使用工厂模式的意图便是定义一个用于创建对象的接口,让子类决定实例化哪一个类。它使得一个类的实例化延迟到其子类。

考虑这种情况,游戏中背包可以存放道具(Item)和装备(Equipment),道具可使用可堆叠不可装备,装备可装备不可使用不可堆叠。他们都继承自物品(Stuff)。定义如下

public enum StuffType
{
	Item,
	Equipment,
	Material,
}

public abstract class Stuff
{

	public int id;
	public readonly StuffType type;
	public Stuff(StuffType stuffType, int stuffId)
	{
		type = stuffType;
		id = stuffId;
	}
}

public class Item : Stuff
{
	public Item(int stuffId):base(StuffType.Item, stuffId)
	{
	}
}

public class Equipment : Stuff
{
	public Equipment(int stuffId):base(StuffType.Equipment, stuffId)
	{
	}
}

当我们需要根据类型创建装备或者道具的时候(例如掉落时)应该怎么办呢?你可能想到了简单工厂:

public static class StuffFactory
{
	public static Stuff CreateStuff(StuffType stuffType, int stuffId)
	{
		Stuff stuff = null;
		switch (stuffType) {
		case StuffType.Item:
			stuff = new Item (stuffId);
			break;
		case StuffType.Equipment:
			stuff = new Equipment (stuffId);
			break;
		}
		return stuff;
	}
}

使用:

		Stuff st = StuffFactory.CreateStuff (StuffType.Equipment, 10);

恩,这样还不错。这个时候策划微笑着想你走来,你一看不妙想赶紧请假走人,策划一把抢过你的请假单,对你说“有个需求很简单,我需要增加一个材料类型,不能使用可以堆叠,可以用来合成道具或者装备”。你拿出了策划发誓不增加物品类型的录音,然而并没有什么卵用。

我们需要增加一个类,并且需要修改StuffFactory,这可能并不是你想要的,因为这违背了开闭原则(对扩展开放,对修改关闭)。所以可以考虑使用下面的方法:

public interface IFactory
{
	Stuff CreateStuff(int stuffId);
}

public class ItemFactory:IFactory
{
	public Stuff CreateStuff(int stuffId)
	{
		return new Item (stuffId);
	}
}

public class EquipmentFactory:IFactory
{
	public Stuff CreateStuff(int stuffId)
	{
		return new Equipment (stuffId);
	}
}

使用:

		IFactory stuffFactory = null;
		StuffType stype = StuffType.Item;
		//TODO:
		switch (stype) {
		case StuffType.Item:
			stuffFactory = new ItemFactory ();
			break;
		case StuffType.Equipment:
			stuffFactory = new EquipmentFactory ();
			break;
		}
		Stuff stuff = stuffFactory.CreateStuff (9);
这就是工厂方法模式。它将类型的判定交给了用户来判断,没需要增加一个类型,原有的工厂不需要做修改,而用户则需要增加一个case选项。

当我们需要增加一个材料类型时,需要为StuffType这个枚举类型添加一个项Material,并增加这些代码:

public class Material:Stuff
{
	public Material(int stuffId):base(StuffType.Material, stuffId)
	{
	}
}

public class MaterialFactory:IFactory
{
	public Stuff CreateStuff(int stuffId)
	{
		return new Material (stuffId);
	}
}

工厂方法模式虽然遵守了开闭原则,但是缺点也很明显,需要为每一个类创建一个工厂类,而且为了保证多态,我们没办法将工厂类设置为静态类。

或者我们可以考虑使用泛型来解决问题:

public class TFactory<T> : IFactory where T: Stuff,new()
{
	public Stuff CreateStuff(int stuffId)
	{
		T ret = new T ();
		ret.id = stuffId;
		return ret;
	}
}

我们需要为每一个类添加默认构造函数,例如:

	public Item():base(StuffType.Item, 0)
	{
	}

使用:

		IFactory sf = null;
		StuffType tstype = StuffType.Equipment;
		//TODO:
		switch (tstype) {
		case StuffType.Item:
			sf = new TFactory<Item> ();
			break;
		case StuffType.Equipment:
			sf = new TFactory<Equipment> ();
			break;
		case StuffType.Material:
			sf = new TFactory<Material> ();
			break;
		}
		Stuff tstuff = sf.CreateStuff (8);

或者使用静态类:

public static class TStaticFactory
{
	public static T CreateStuff<T>(int stuffId) where T: Stuff,new()
	{
		T ret = new T ();
		ret.id = stuffId;
		return ret;
	}
}

使用:

		StuffType tsstype = StuffType.Item;
		Stuff tsstuff = null;
		int id = 7;
		//TODO:
		switch (tsstype) {
		case StuffType.Item:
			tsstuff = TStaticFactory.CreateStuff<Item> (id);
			break;
		case StuffType.Equipment:
			tsstuff = TStaticFactory.CreateStuff<Equipment> (id);
			break;
		case StuffType.Material:
			tsstuff = TStaticFactory.CreateStuff<Material> (id);
			break;
		}

似乎非静态的工厂会好一点,但是仍然不可避免的要每次创建一个工厂实例。


实际情况下,似乎简单工厂运用的更广泛一些,虽然违背了开闭原则,但是写起了比较方便,适用于轻量级的继承关系。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值