在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
介绍
在策略模式(Strategy Pattern)中,一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
使用场景
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
优缺点及注意
优点
- 算法可以自由切换。
- 避免使用多重条件判断。
- 扩展性良好。
缺点
- 策略类会增多。
- 所有策略类都需要对外暴露。
注意
如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题。
实现
策略角色
1 2 3 4 5 6
| public interface Strategy {
public void algorithmInterface(); }
|
以下三个实现类为具体的策略角色
1 2 3 4 5 6
| public class ConcreteStrategyA implements Strategy{ @Override public void algorithmInterface() { System.out.println("具体的策略A"); } }
|
1 2 3 4 5 6
| public class ConcreteStrategyB implements Strategy { @Override public void algorithmInterface() { System.out.println("具体的策略B"); } }
|
1 2 3 4 5 6 7
| public class ConcreteStrategyC implements Strategy { @Override public void algorithmInterface() { System.out.println("具体的策略C"); } }
|
Context上下文
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Context { private Strategy strategy;
public Context(Strategy strategy) { this.strategy = strategy; }
public void executeStrategy() { strategy.algorithmInterface(); } }
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Client {
public static void main(String[] args) { Context context;
context = new Context(new ConcreteStrategyA()); context.executeStrategy();
context = new Context(new ConcreteStrategyB()); context.executeStrategy();
context = new Context(new ConcreteStrategyC()); context.executeStrategy(); } }
|
结果:
使用Spring实现策略模式+工厂模式
1、实现策略类
1 2 3 4
| public interface Strategy { void doSomething(); }
|
1 2 3 4 5 6 7 8 9 10 11 12
| @Component public class ConcreteStrategy1 implements Strategy { @Override public void doSomething() { System.out.println("具体策略1的运算法则..."); }
@Override public String toString() { return "具体策略1"; } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| @Component public class ConcreteStrategy2 implements Strategy { @Override public void doSomething() { System.out.println("具体策略2的运算法则..."); }
@Override public String toString() { return "具体策略2"; } }
|
1 2 3 4 5 6 7 8 9 10 11 12
| @Component public class DefaultStrategy implements Strategy { @Override public void doSomething() { System.out.println("默认策略的运算法则..."); }
@Override public String toString() { return "默认策略"; } }
|
2、实现工厂类
1 2 3 4 5 6 7 8 9 10
| @Component public class StrategyFactory { @Autowired private Map<String, Strategy> strategyMap;
public Strategy getBy(String strategyName) { return strategyMap.get(strategyName); } }
|
Spring会自动将Strategy接口的实现类注入到这个Map中(前提是实现类得是交给Spring 容器管理的),这个Map的key为bean id,可以用@Component(value = “xxx”)的方式设置,如果直接用默认的方式的话,就是首字母小写。value值则为对应的策略实现类。
测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13
| @SpringBootTest class SpringbootDemoApplicationTests {
@Autowired private ApplicationContext context;
@Test public void test() { context.getBean(StrategyFactory.class).getBy("concreteStrategy1").doSomething(); context.getBean(StrategyFactory.class).getBy("concreteStrategy2").doSomething(); }
}
|
执行结果如下:
1 2
| 具体策略1的运算法则... 具体策略2的运算法则...
|
3、别名转换
上面测试类调用的使用使用的bean id,实际业务中应该是将传入的code转义成对应的策略类的bean id。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Component @PropertySource("classpath:application.properties") @ConfigurationProperties(prefix = "strategy") public class StrategyAliasConfig { private HashMap<String, String> aliasMap;
public static final String DEFAULT_STATEGY_NAME = "defaultStrategy";
public HashMap<String, String> getAliasMap() { return aliasMap; }
public void setAliasMap(HashMap<String, String> aliasMap) { this.aliasMap = aliasMap; }
public String of(String entNum) { return aliasMap.get(entNum); } }
|
配置文件application.properties
1 2
| strategy.aliasMap.strategy1=concreteStrategy1 strategy.aliasMap.strategy2=concreteStrategy2
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Component public class StrategyFactory { @Autowired private StrategyAliasConfig strategyAliasConfig;
@Autowired private Map<String, Strategy> strategyMap;
public Strategy getBy(String strategyName) { String name = strategyAliasConfig.of(strategyName); if (name == null) { return strategyMap.get(StrategyAliasConfig.DEFAULT_STATEGY_NAME); } Strategy strategy = strategyMap.get(name); if (strategy == null) { return strategyMap.get(StrategyAliasConfig.DEFAULT_STATEGY_NAME); } return strategy;
} }
|
测试类:
1 2 3 4 5 6 7 8 9 10 11 12 13
| @SpringBootTest class SpringbootDemoApplicationTests {
@Autowired private ApplicationContext context;
@Test public void test() { context.getBean(StrategyFactory.class).getBy("strategy1").doSomething(); context.getBean(StrategyFactory.class).getBy("strategy2").doSomething(); }
}
|
执行结果如下:
1 2
| 具体策略1的运算法则... 具体策略2的运算法则...
|
参考
策略模式及使用Spring实现策略模式+工厂模式