本文原文链接地址:http://nullpointer.pw/design-patterns-strategy.html
类型:行为型模式
意图:定义一系列算法,不同算法策略可以相互替换,并且互不影响。
主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。
使用场景:一个系统需要动态地在几种算法中选择一种。
角色
- 策略上下文角色:持有抽象策略角色的引用,访问策略的入口
- 抽象策略角色
- 具体策略角色
UML
实战
以抽奖活动发奖为例,奖品多种多样,可能是现金奖,话费奖品,实物奖等等,每种奖品的发放方式都不一样,比如现金是直接转账,话费奖品是调用运营商提供接口发放,实物奖需要人工快递寄送。在未采用策略模式之前,少不了使用 if...else...来判断发放,当增加一种奖品类型时,就需要增加 if 判断。而采取策略模式之后,只需实现一个策略类即可,对原来的逻辑无需做任何改动,也不会影响其他策略的正常逻辑。
本文示例UML图
定义抽象策略接口
/**
* @author WeJan
* @since 2020-02-06
*/
public interface PrizeSendStrategy {
String DEFAULT = "default";
String MONEY = "money";
String IN_KIND = "in_kind";
String CALL_CHARGE = "call_charge";
String type();
void doSend();
}
实现具体的策略
@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("不发奖");
}
}
实现对抽象策略封装的上下文对象
/**
* @author WeJan
* @since 2020-02-06
*/
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));
}
}
测试
/**
* @author WeJan
* @since 2020-02-06
*/
@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();
}
}
输出结果为:
发放现金奖品