面向对象设计模式之工厂模式,星际争霸种族实现举例

版本声明:转载请注明出处。未经允许,禁止商业用途。

定义

定义了一个创建对象的接口,但是由子类决定要实例化的类是哪一个。工厂方法把类的实例化推迟到子类中。

实现方法

基类Product定义工厂方法所创建的对象的接口,派生类ConcreteProduct实现Product中的接口。

基类Creator定义一个创建Product的抽象工厂方法,派生类ConcreteCreator实现这个抽象工厂方法,由ConcreteCreator决定要实例化哪种ConcreteProduct。

需要说明的是工厂方法可以不是抽象的,可以让工厂方法默认产生某种ConcreteProduct。工厂方法也不是必须参数化。如果工厂只产生一种对象,那么就不需要参数化。

效果

工厂模式帮助我们将Product的实现和使用解耦。如果增加ConcreteProduct或者改变ConcreteProduct的实现,Product和Creator并不会受影响,更重要的是使用Product的客户不受影响。只需要修改对应的ConcreteCreator。

实例

很多程序员,当然还有非程序员都喜欢玩即时战略游戏。为了提高大家的兴趣,我为大家举一个例子。实现一个即时战略游戏中生产不同种族不同类型的士兵的组件。考虑篇幅,每个种族我都只实现了一种类型的士兵。感兴趣的话,读者可以自行添加其它类型的士兵。

角色对应关系:

Soldier是Product。HumanInfantry(人族步兵)和OrcInfantry(兽族步兵)是ConcreteProduct。

SoldierTrainingGroud是Creator。HumanSoldierTrainingGroud和OrcSoldierTrainingGroud是ConcreteCreator。

SoldierTest模拟客户,创建和使用具体类型的Soldier。

Java代码如下

Soldier.java:

package soldierfactory;

/* 这个类不依赖于任何具体类。
 * 这里体现了面向对象设计原则中的依赖倒置原则,
 * 依赖抽象,但是不依赖具体类。
 * 具体类依赖于抽象类Soldier,因为它们实现了Soldier的接口,
 * 这就是依赖倒置。*/
public abstract class Soldier {
	String name;
	/* 还可以定义攻击力、防御力、射程、移动速度、满血值、消耗黄金数量、消耗木材数量等 */
	String getName() {
		return name;
	}
	
	void provideResource() {
		System.out.println("providing gold and wood");
	}
	
	void train() {
		System.out.println("training");
	}
	
	void equip() {
		System.out.println("equipping");
	}
}

SoldierTrainingGroud.java

package soldierfactory;

/* 因为类里有抽象方法,所以类是抽象类。 
 * 与Soldier类似,这里也体现了依赖倒置原则。
 * requireSoldier()定义了一个框架。
 * 明确了具体类可以做哪些事情,
 * 但是具体每件事情如何做,具体类可以自己决定。
 * 另外,requireSoldier()并不知道哪个子类会最终做这些事情。 */
public abstract class SoldierTrainingGroud {
	/* 工厂方法createSoldier()使类的实例化推迟到子类中。
	 * 工厂方法是abstract的,所以子类必须实现它,实现类的实例化。
	 * 工厂方法返回一个Product
	 * */
	abstract Soldier createSoldier(String type);
	
	public Soldier requireSoldier(String type) {
		/* 将变化的部分,即实例化具体类的代码从应用中抽离,使它不会干扰应用的其它部分。
		 * 客户使用接口createSoldier(),
		 * 即针对接口编程,而不是针对实现编程。
		 * 针对接口编程,可以隔离变化,
		 * 通过多态,可以使用任何实现了该接口的具体类。
		 * 如果直接使用具体类,一旦加入新的具体类,就需要修改代码,
		 * 这使得requireSoldier()无法对修改关闭 */
		Soldier soldier = createSoldier(type);
		System.out.println("producting a "+ soldier.name);
		soldier.provideResource();
		soldier.train();
		soldier.equip();
		return soldier;
	}
}

HumanInfantry.java:

package soldierfactory;

public class HumanInfantry extends Soldier{
	HumanInfantry(){
		name = "Human Infantry";
		/* 还可以对攻击力、防御力、射程、移动速度、满血值、消耗黄金数量、消耗木材数量等进行赋值 */
	}
	
	/* 按需覆盖基类Soldier中的方法 */
	void provideResource() {
		/* 制造不同的兵种,消耗的黄金和木材数量不同 */
		System.out.println("providing gold and wood for Human Infantry");
	}
	
	void train() {
		/* 训练不同的兵种,所需的时间不同 */
		System.out.println("training Human Infantry");
	}
	
	void equip() {
		/* 装备不同的兵种,所需的时间不同 */
		System.out.println("equipping Human Infantry");
	}
}

HumanSoldierTrainingGroud.java:

package soldierfactory;

public class HumanSoldierTrainingGroud extends SoldierTrainingGroud{
	/* 实现SoldierTrainingGroud中的抽象方法createSoldier()
	 * 不同种族的士兵训练场可以生产不同类型的士兵 */
	Soldier createSoldier(String type) {
		/* 生产步兵 */
		if(type.equals("infantry")) {
			return new HumanInfantry();
		} else return null;
		/* 这里也可以添加cavalry(骑兵)、archer(弓箭手)*/
	}
}

OrcInfantry.java:

package soldierfactory;

public class OrcInfantry extends Soldier{
	OrcInfantry(){
		name = "Orc Infantry";
	}
	
	void provideResource() {	
		System.out.println("providing gold and wood for Orc Infantry");
	}
	
	void train() {
		System.out.println("training Orc Infantry");
	}
	
	void equip() {
		System.out.println("equipping Orc Infantry");
	}
}

OrcSoldierTrainingGroud.java:

package soldierfactory;

public class OrcSoldierTrainingGroud extends SoldierTrainingGroud{
	Soldier createSoldier(String type) {
		if (type.equals("infantry")) {
			return new OrcInfantry();
		} else return null;
	}
}

SoldierTest.java:

package soldierfactory;

public class SoldierTest {
	public static void main(String[] args) {
		SoldierTrainingGroud humanSoldierTrainingGroud = new HumanSoldierTrainingGroud();
		SoldierTrainingGroud orcSoldierTrainingGroud = new OrcSoldierTrainingGroud();
		
		/* 生产一个人族步兵。 
		 * 客户使用Product类(Soldier类),不直接使用ConcreteProduct类(HumanInfantry类),
		 * 即针对接口编程,而不是针对实现编程。
		 * 通过多态,实际可以使用任何实现了该接口的具体类。 */
		Soldier soldier1 = humanSoldierTrainingGroud.requireSoldier("infantry");
		System.out.println("producted a "+soldier1.getName()+"\n");
		/* 啊啊啊,吼吼,我要去战斗! */
		
		/* 生产一个兽族步兵 */
		Soldier soldier2 = orcSoldierTrainingGroud.requireSoldier("infantry");
		System.out.println("producted a "+soldier2.getName()+"\n");
	}

}

运行结果:

producting a Human Infantry
providing gold and wood for Human Infantry
training Human Infantry
equipping Human Infantry
producted a Human Infantry

producting a Orc Infantry
providing gold and wood for Orc Infantry
training Orc Infantry
equipping Orc Infantry
producted a Orc Infantry

 

谢谢阅读。欢迎提问。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值