本文最后更新于:2020年12月27日 中午
类型:行为型模式
意图:定义一系列算法,不同算法策略可以相互替换,并且互不影响。
主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。
使用场景:一个系统需要动态地在几种算法中选择一种。
设计模式系列文章目录
角色
策略上下文角色:持有抽象策略角色的引用,访问策略的入口
抽象策略角色
具体策略角色
UML
实战 以抽奖活动发奖为例,奖品多种多样,可能是现金奖,话费奖品,实物奖等等,每种奖品的发放方式都不一样,比如现金是直接转账,话费奖品是调用运营商提供接口发放,实物奖需要人工快递寄送。在未采用策略模式之前,少不了使用 if…else…来判断发放,当增加一种奖品类型时,就需要增加 if 判断。而采取策略模式之后,只需实现一个策略类即可,对原来的逻辑无需做任何改动,也不会影响其他策略的正常逻辑。
本文示例UML图
定义抽象策略接口 public interface PrizeSendStrategy { String DEFAULT = "default" ; String MONEY = "money" ; String IN_KIND = "in_kind" ; String CALL_CHARGE = "call_charge" ; String type () ; void doSend () ; }
实现具体的策略 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 @Component public class CallChargePrizeSendStrategy implements PrizeSendStrategy { @Override public String type () { return CALL_CHARGE; } @Override public void doSend () { System.out.println("发放话费奖品" ); } }@Component public class MoneyPrizeSendStrategy implements PrizeSendStrategy { @Override public String type () { return MONEY; } @Override public void doSend () { System.out.println("发放现金奖品" ); } }@Component public class InKindPrizeSendStrategy implements PrizeSendStrategy { @Override public String type () { return IN_KIND; } @Override public void doSend () { System.out.println("发放实物奖品" ); } }@Component public class EmptyPrizeSendStrategy implements PrizeSendStrategy { @Override public String type () { return DEFAULT; } @Override public void doSend () { System.out.println("不发奖" ); } }
实现对抽象策略封装的上下文对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class PrizeSendContext { private PrizeSendStrategy prizeSendStrategy; public PrizeSendContext () { } public void setPrizeSendStrategy (PrizeSendStrategy prizeSendStrategy) { this .prizeSendStrategy = prizeSendStrategy; } public void executePrizeSendStrategy () { prizeSendStrategy.doSend(); } }
抽取策略工厂 客户端需要判断要使用哪一个具体的策略类,若还是按照传统的方法 if…else…来判断策略模式就没有意义了,因此策略模式一般都是结合其他模式共同使用。本文中策略类使用 String 来标识,也可以在策略类中增加抽象方法,返回值为枚举类型。
@Component public class PrizeSendStrategyFactory implements ApplicationContextAware { private static final Map<String, PrizeSendStrategy> PRIZE_SEND_STRATEGY_MAP = new HashMap<>(); public static PrizeSendStrategy getPrizeSendStrategy (String strategyKey) { return PRIZE_SEND_STRATEGY_MAP.getOrDefault(strategyKey, PRIZE_SEND_STRATEGY_MAP.get(DEFAULT)); } @Override public void setApplicationContext (ApplicationContext applicationContext) throws BeansException { Map<String, PrizeSendStrategy> beans = applicationContext.getBeansOfType(PrizeSendStrategy.class); beans.values().forEach(bean -> PRIZE_SEND_STRATEGY_MAP.put(bean.type(), bean)); } }
测试 @RunWith(SpringRunner.class) @SpringBootTest(classes = App.class) public class StrategyTest { @Test public void test () { PrizeSendContext sendContext = new PrizeSendContext(); sendContext.setPrizeSendStrategy(PrizeSendStrategyFactory.getPrizeSendStrategy("money" )); sendContext.executePrizeSendStrategy(); } }
输出结果为:
示例代码
参考