设计模式(2)--行为型--策略模式

343 阅读2分钟

一、策略模式简介

翻看了大部分博客,都会讲策略模式解决“在有多种算法相似的情况下,使用 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、经典的策略模式

image.png

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);
    }
}

三、策略模式后记

怎么快速判断是否需要用策略模式,你可以想想下。