场景: 商场搞活动,根据客户购买商品的金额,收费时给与不同的打折,比如,购买 金额>=2000 的打八折(0.8),金额 500 ~ 1000 的,打九折(0.9),购买金额 0 ~ 500 的九五折(0.95),根据不同的金额走不同计算策略逻辑。
public interface Strategy { /** * 采用策略 */ String strategy(); /** * 计算方法逻辑 */ void algorithm(); }其中strategy方法返回当前策略的唯一标识,algorithm则是该策略的具体执行的计算逻辑。下面是Strategy接口的两个实现类:
public class ConcreteStrategyA implements Strategy { @Override publicString strategy() { return StrategySelector.strategyA.getStrategy(); } @Override publicvoid algorithm() { System.out.println("process with strategyA..."); } } publicclass ConcreteStrategyB implements Strategy { @Override publicString strategy() { return StrategySelector.strategyB.getStrategy(); } @Override publicvoid algorithm() { System.out.println("process with strategyB..."); } } publicclass ConcreteStrategyC implements Strategy { @Override publicString strategy() { return StrategySelector.strategyC.getStrategy(); } @Override publicvoid algorithm() { System.out.println("process with strategyC..."); } }自定义策略选择枚举 **StrategySelector**:
@Getter publicenum StrategySelector { // 堆代码 duidaima.com strategyA(1,"strategyA"), strategyB(2,"strategyB"), strategyC(3,"strategyC"); private Integer code; private String strategy; StrategySelector(Integer code, String strategy) { this.code = code; this.strategy = strategy; } }然后定义一个StrategyRunner接口用来表示策略的调度器:
public interface StrategyRunner { void execute(String strategy); }execute方法内部通过判断strategy的值来决定具体执行哪一个策略。
public class StrategyRunnerImpl implements StrategyRunner { privatestatic final List<Strategy> STRATEGIES = Arrays.asList(new ConcreteStrategyA(), new ConcreteStrategyB(), new ConcreteStrategyC()); privatestatic Map<String, Strategy> STRATEGY_MAP = Maps.newHashMap(); static { STRATEGY_MAP = STRATEGIES.stream().collect(Collectors.toMap(Strategy::strategy, s -> s)); } @Override publicvoid execute(String strategy) { STRATEGY_MAP.get(strategy).algorithm(); } }在StrategyRunnerImpl内部,定义了一个STRATEGIES列表来保存所有Strategy实现类的实例,以及一个叫做STRATEGY_MAP的Map来保存strategy和Strategy实例之间的对应关系,static块中的代码用于从STRATEGIES列表构造STRATEGY_MAP。这样,在execute方法中就可以很方便地获取到指定strategy的Strategy实例。
@Component publicclass ConcreteStrategyA implements Strategy { @Override publicString strategy() { return StrategySelector.strategyA.getStrategy(); } @Override publicvoid algorithm() { System.out.println("process with strategyA..."); } } @Component publicclass ConcreteStrategyB implements Strategy { @Override publicString strategy() { return StrategySelector.strategyB.getStrategy(); } @Override publicvoid algorithm() { System.out.println("process with strategyB..."); } } @Component publicclass ConcreteStrategyC implements Strategy { @Override publicString strategy() { return StrategySelector.strategyC.getStrategy(); } @Override publicvoid algorithm() { System.out.println("process with strategyC..."); } }然后,定义一个StrategyConfig配置类,用于向容器注入一个StrategyRunner:
@Configuration public class StrategyConfig { @Bean public StrategyRunner runner(List<Strategy> strategies) { Map<String, Strategy> strategyMap = strategies.stream().collect(Collectors.toMap(Strategy::strategy, s -> s)); return flag -> strategyMap.get(flag).algorithm(); } }不难发现,strategyRunner方法的实现,其中的逻辑与之前的StrategyRunnerImpl几乎完全相同,也是根据一个List<Strategy>来构造一个Map<String, Strategy>。只不过,这里的strategies列表不是我们自己构造的,而是通过方法参数传进来的。由于strategyRunner标注了Bean注解,因此参数上的List<Strategy>实际上是在Spring Boot初始化过程中从容器获取的,所以我们之前向容器中注册的那两个实现类会在这里被注入。
@Autowired private StrategyRunner strategyRunner;然后直接使用strategyRunner就行了:
@RestController @RequestMapping(value = "/designPatterns") public class DesignPatternController { @Autowired private StrategyRunner strategyRunner; @GetMapping(value = "/algorithm") public void algorithm(@RequestParam("strategy") String strategy) { strategyRunner.execute(strategy); } }访问接口,控制台输出如下:
process with strategyA...