《Java设计模式之策略模式》

《二 》策略模式

  相信很多人都玩过魔兽世界这款游戏,它里面的战士有三种姿态:防御、狂暴、战斗,那么在不同的场景下我们需要使用不通的姿态,比如当MT抗怪就需要使用防御姿态,战场需要使用战斗姿态,而输出可能就要使用到狂暴姿态。那么在Java程序中使用硬编码的方式实现如下:
//战士抽象类
public abstract class Warrior {
	public abstract void changeStance();
}
//狂暴战
public class FuryWarrior extends Warrior{
	@Override
	public void changeStance() {
		System.out.println("切换至狂暴姿态");
	}

}
//防战
public class TankWarrior extends Warrior {
	@Override
	public void changeStance() {
		System.out.println("切换到防御姿态");
	}
}
//武器战
public class WeaponWarrior extends Warrior {
	@Override
	public void changeStance() {
		System.out.println("切换至战斗姿态");
	}	
}
//测试类
public class WarriorTest {
	@Test
	public void testWarrior(){
		String type = "战场";
		Warrior warrior;
		switch (type) {
		case "MT":
			warrior = new TankWarrior();
			warrior.changeStance();
			break;
		case "战场":
			warrior = new WeaponWarrior();
			warrior.changeStance();
			break;
		case "输出":
			warrior = new FuryWarrior();
			warrior.changeStance();
			break;
		default:
			break;
		}
	}
}

   通过上面这种硬编码的方式,在客户端进行逻辑判断(使用switch或者if-else)可以实现战士在不同场景下多的姿态切换,但是假设现在暴雪给战士又添加了一个新的姿态或者新的场景需要判断,那么就必须要在客户端代码中修改源码,非常不便于扩展,而且复杂的switch或者if-else语句都是非常不便于维护的,这时候策略模式就闪亮登场了!

  策略模式:定义了算法家族,分别封装起来,让它们之间可以相互替换,此模式让算法的变化不会影响到使用算法的客户端。

  那么现在我们使用策略模式再把上面的场景实现一次:

//战士类(环境角色)
public class Warrior {
	private Stance stance;
	public Warrior(Stance stance) {
		this.stance = stance;
	}
	public void changeStance(){
		stance.getStance();
	}
}
//姿态接口(抽象策略角色)
public interface Stance {
	void getStance();
}
//防御姿态
public class TankStance implements Stance {
	@Override
	public void getStance() {
		System.out.println("切换到防御状态");
	}
}
//狂暴姿态
public class FuryStance implements Stance {
	@Override
	public void getStance() {
		System.out.println("切换至狂暴状态");
	}
}
//武器姿态
public class WeaponStance implements Stance {
	@Override
	public void getStance() {
		System.out.println("切换至战斗状态");
	}
}
//测试类
public class WarriorTest {
	@Test
	public void testWarrior(){
		Warrior w1 = new Warrior(new TankStance());
		w1.changeStance();
		
		Warrior w2 = new Warrior(new FuryStance());
		w2.changeStance();
		
		Warrior w3 = new Warrior(new WeaponStance());
		w3.changeStance();
	}
}

  通过使用策略模式实现战士切换姿态的场景需求时,如果需要添加新的姿态或者场景,那么只需要添加一个算法就行了,相比硬编码的方式更容易维护和扩展。策略模式的重心不是在算法,而是封装算法,通过组织和调用算法让程序结构更加灵活。


  策略模式的优点:

        (1) 策略模式定义了一系列的算法,所有这些算法都是完成相同的工作,只是实现不同,可以互相替换,减少了客户端和算法类之间的耦合

        (2) 策略模式中的算法都可以进行单独的单元测试

        (3) 策略模式避免了复杂的逻辑判断语句(switch或if-else)


  策略模式的缺点:

       (1) 通过上面的示例返现,客户端必须知道所有的策略类,并且知道应该使用哪一个策略类。

       (2) 如果算法种类过多,那么策略类的数量就会过于庞大。


   扩展:

       使用简单工厂模式配合策略模式,可以让客户端不用自己来决定该使用哪一个策略,代码如下:

//生产状态对象的工厂类
public class StanceFactory {
	public static Stance getStance(String type){
		switch (type) {
		case "MT":
			return new TankStance();
		case "输出":
			return new FuryStance();
		case "战场":
			return new WeaponStance();
		default:
			return null;
		}
	}
}
//测试类
public class WarriorTest {
	@Test
	public void testWarrior(){
		String type = "战场";
		Stance stance = StanceFactory.getStance(type);
		if (stance!=null){
			Warrior warrior = new Warrior(stance);
			warrior.changeStance();
		}
	}
}

  通过配合使用简单工厂模式,我们可以让客户端只需传入场景就可以由工厂来选择对应的策略,虽然解决了客户端判断策略的压力,但是工厂类的switch语句又导致程序的维护性和扩展行较差。我们可以使用反射和配置文件来对工厂类进行改进从而解决这个问题。代码如下:

//生产状态对象的工厂类
public class StanceFactory {
	private static Map<String, String> data;
	static{
		//这里使用Map模拟配置文件
		data = new HashMap<>();
		data.put("战场", "cn.eragon.domain.WeaponStance");
		data.put("MT", "cn.eragon.domain.TankStance");
		data.put("输出", "cn.eragon.domain.FuryStance");
	}
	public static Stance getStance(String type){
		String className = data.get(type);
		if (className!=null){
			try {
				return (Stance) Class.forName(className).newInstance();
			} catch (Exception e) {
				throw new RuntimeException(e);
			} 
		}
		return null;
	}
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值