背景
项目一开始需要针对两个功能添加终止功能,因为只涉及两个功能,所以就偷懒直接用if-else模式处理了,心想着以后有机会在重构吧,没想到来的这么突然,又需要对几个功能点添加终止功能,就利用这个契机索性对代码进行重构了。
解决
由于项目原因,需求我们用(利用不同code值选择不同音频设备处理实际需求)代替。
话不多说,我们直接勺代码。
项目结构图
各类代码
-
TypeEnum枚举
public enum TypeEnum { MP3(0,"我是mp3"), MP4(1,"我是mp4"), MP5(2,"我是mp5"), ; private int code; private String msg; TypeEnum(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }
-
StrategyTypeHandler注解
@Documented @Inherited @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface StrategyTypeHandler { TypeEnum value(); }
-
Strategy接口
/** * 策略接口 **/ public interface Strategy { /** * 每个策略执行的方法 **/ String custom(String param); }
-
XxxStrategy类(具体执行策略的类,均类似所以只写一个例子)
/** * @ClassName Mp3Strategy * @Description 如果类型为mp3时需执行的方法 **/ @Component @StrategyTypeHandler(TypeEnum.MP3) //标注每个类所支持的类型 public class Mp3Strategy implements Strategy { @Override public String custom(String param) { System.out.println("我是处理MP3格式的方法"); //todo 书写自己的业务处理逻辑 return "MP3:" + param; } }
-
StrategyContext类
/** * @ClassName StrategyContext * @Description 策略容器上下文 **/ @Component public class StrategyContext { private final Map<Integer, Strategy> handlerMap = new HashMap<>(); public Strategy getStrategy(Integer type) { return handlerMap.get(type); } public void putStrategy(Integer code, Strategy strategy) { handlerMap.put(code, strategy); } }
-
StrategyListener类
/** * @ClassName StrategyListener * @Description 服务启动后初始化策略容器 **/ @Component public class StrategyListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { Map<String, Object> beans = event.getApplicationContext().getBeansWithAnnotation(StrategyTypeHandler.class); StrategyContext strategyContext = event.getApplicationContext().getBean(StrategyContext.class); beans.forEach((name, bean) -> { StrategyTypeHandler typeHandler = bean.getClass().getAnnotation(StrategyTypeHandler.class); strategyContext.putStrategy(typeHandler.value().getCode(), (Strategy) bean); }); } }
-
TestStrategyController模拟调用类
/** * @ClassName TestStrategyController * @Description 模拟测试策略模式控制器 **/ @RestController @RequestMapping("strategy") public class TestStrategyController { @Resource private StrategyContext strategyContext; /** * 根据不同的code值选则不同的处理模式来处理 * code为0时选择mp3处理,为1时选择mp4处理,为2时选择mp5处理 **/ @GetMapping("test") public String testStrategy(@RequestParam(value = "code") Integer code, @RequestParam(value = "param") String param) { Strategy strategy = strategyContext.getStrategy(code); if (strategy == null) { return "不支持的格式"; } return strategy.custom(param); } }
-
到这里代码架构就可以了,我们可以通过自己写的 Controller 类传入不同的 code 进行测试。
扩展
当我们改成完全策略模式后,任你类别千千万,我们都可以以不变应万变。当需要支持新的类别时(例如:Mp8/Mp6),我们只需要改动两个地方:
- 在TypeEnum枚举中添加新支持格式的枚举
- 添加一个Xxx类实现Strategy接口,并在类上加上StrategyTypeHandler标注其格式类型
小结
相信看完了上面代码的例子,即使你对策略模式理论还不能完全理解,但是也足够解决项目中类似的实际问题了。
以上代码源码地址:Git-Hub:strategy-demo