一、策略模式简介
翻看了大部分博客,都会讲策略模式解决“在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。”,经典的策略模式并没有解决这个问题额。
策略模式定义的一些策略彼此间独立,可相互切换,新增策略只需要新增一个策略类即可达到效果。
缺点明显,就是调用方必须知道有哪些策略。
二、经典策略模式不足及其改进
在讲经典的策略模式前,先写能达到同样功能的常规代码。接下来以魂斗罗中三类枪为例来描述。
2.1、常规代码
// 一个工具类搞定3种算法
public class Util {
public static void mGunShoot() {
System.out.println("MachineGun机关枪射击");
}
public static void sGunShoot() {
System.out.println("SpreadGun散弹枪射击");
}
public static void fGunShoot() {
System.out.println("Flamethrower螺旋火焰枪射击");
}
}
// 调用方
class Test {
public static void main(String[] args) {
shoot("M");
}
private static void shoot(String type) {
// if else判断
if ("M".equals(type)) {
Util.mGunShoot();
} else if ("S".equals(type)) {
Util.sGunShoot();
} else if ("F".equals(type)) {
Util.fGunShoot();
}
}
}
这里的问题:如果算法实现比较复杂,一个Util中代码量轻松超过1000+,如果后续新增一个算法,代码量还会累加,同时在调用方这里也得加上一个else if判断。
2.2、经典的策略模式
interface Strategy {
String getType();
void shoot();
}
public class FGunStrategy implements Strategy {
@Override
public String getType() {
return "F";
}
@Override
public void shoot() {
System.out.println("Flamethrower螺旋火焰枪射击");
}
}
public class MGunStrategy implements Strategy {
@Override
public String getType() {
return "M";
}
@Override
public void shoot() {
System.out.println("MachineGun机关枪射击");
}
}
public class SGunStrategy implements Strategy {
@Override
public String getType() {
return "S";
}
@Override
public void shoot() {
System.out.println("SpreadGun散弹枪射击");
}
}
还需要一个策略上下文,方便调用方使用,体现面向对象。
public class StrategyContext {
public Strategy mStrategy;
public void setStrategy(Strategy strategy) {
mStrategy = strategy;
}
public void shoot() {
mStrategy.shoot();
}
}
class Test {
public static void main(String[] args) {
shoot("M");
}
private static void shoot(String type) {
StrategyContext context = new StrategyContext();
// 这里还得用if else 判断一下,怎么就少了一层if else呢?
if ("M".equals(type)) {
context.setStrategy(new MGunStrategy());
} else if ("S".equals(type)) {
context.setStrategy(new SGunStrategy());
} else if ("F".equals(type)) {
context.setStrategy(new FGunStrategy());
}
context.shoot();
}
}
经典的策略模式并没有解决if else判断问题,仅仅是将多种算法拆开,调用时体现面向对象,操作的是StrategyContext,调用方还得按需选择策略,有点麻烦。
2.3、策略上下文StrategyContext改进
public class StrategyContext {
public List<Strategy> mStrategies = new ArrayList<>();
public StrategyContext() {
// 高端玩家已经不仅仅限于直接添加的方式,而是通过注解注入。
mStrategies.add(new FGunStrategy());
mStrategies.add(new SGunStrategy());
mStrategies.add(new MGunStrategy());
}
public void shoot(String type) {
for (Strategy strategy : mStrategies) {
if (strategy.getType().equals(type)) {
strategy.shoot();
}
}
}
}
策略上下文hold住所有的策略,这里为了方便直接添加了所有的策略,其实可以用更解耦的方式处理比如注解处理器来干这事。
class Test {
public static void main(String[] args) {
shoot("M");
}
private static void shoot(String type) {
StrategyContext context = new StrategyContext();
context.shoot(type);
}
}
三、策略模式后记
怎么快速判断是否需要用策略模式,你可以想想下。