策略模式是一种定义了一系列算法的方法,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法的类之间的耦合.简单来说,策略模式就是将每个算法都封装起来,使他们之间可以互换.
举个例子,比如商场的不同优惠活动,有满100返20、满300返100、全场8折、积分等,不管商场如何搞活动,归根结底都是一系列的算法,这些算法是随时都可能互相替换的.
该模式中包含的角色以及职责:
1)抽象策略角色
是对策略、算法的抽象,通常为接口,定义每个策略、方法必须具有的属性和方法.
2)具体策略角色
实现抽象策略角色,用于具体算法的实现.
3)环境角色
又称Context上下文,持有一个策略类的引用,最终给客户端调用.有承上启下的作用,屏蔽对策略、算法的直接访问,封装可能存在的变化.
UML图如下:
1)抽象策略角色
public interface Strategy { String algorithmlnterface(); }
2)具体策略角色
@Slf4j @Component("concreteStrategyA") public class ConcreteStrategyA implements Strategy { @Override public String algorithmlnterface() { log.info("算法A实现..."); return "算法A实现..."; } }
@Slf4j @Component("concreteStrategyB") public class ConcreteStrategyB implements Strategy { @Override public String algorithmlnterface() { log.info("算法B实现..."); return "算法B实现..."; } }
...以此类推
3)上下文
@Service public class Context { @Autowired private final Map
strategyMap = new ConcurrentHashMap<>(); /** * 通过spring将Strategy的实现类都自动注入到strategyMap中 * @author su * @date 2019-12-09 11:21 * @param strategyMap * @return */ public Context(Map strategyMap) { this.strategyMap.clear(); strategyMap.forEach((k, v) -> this.strategyMap.put(k, v)); } /** * 根据传入的类型获取资源 * @author su * @date 2019-12-09 11:30 * @param strategyType * @return void */ public String getResult(String strategyType){ return strategyMap.get(strategyType).algorithmlnterface(); } }
4)测试类
@Slf4j @RestController @RequestMapping("/test") public class TestController { @Autowired private Context context; /** * 测试策略模式 * * @param strategyType * @return java.lang.String * @author su * @date 2019-12-09 11:41 */ @GetMapping("/strategy/{strategyType}") public String getStrategyResult(@PathVariable("strategyType") String strategyType) { return context.getResult(strategyType); } }
5)测试结果
优点:
1)消除条件语句,避免大量的判断.解决在多种算法相似的情况下,使用if...else所带来的复杂和难以维护
2)算法可以自由切换,扩展性好.(新的算法只需要实现抽象策略)
缺点:
1)所有策略类都需对外暴露,以便算法的选择.
2)策略类多于四个的时候就要考虑使用混合模式解决策略类膨胀的问题了