策略模式基本定义
定义一组算法,将每个算法都封装起来,并且使它们之间可以互换。
策略模式使用场景
- 如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
- 一个系统需要动态地在几种算法中选择一种。例如:消息的发送方式选择,不同银行充值的选择
- 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。
策略模式通用UML
策略模式简单使用
1.定义一个算法策略接口(定义每个策略或算法必须具有的方法和属性)
public interface Strategy {
//算法
void algorithm();
}
2.增加两个算法实现类(实现抽象策略中的操作,该类含有具体的算法。)
public class StrategyA implements Strategy {
@Override
public void algorithm() {
System.out.println("采用策略A计算");
}
}
public class StrategyB implements Strategy {
@Override
public void algorithm() {
System.out.println("采用策略B计算");
}
}
3.定义策略上下文(起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。)
public class StrategyContext {
private Strategy strategy;
//调用策略
public void method(){
strategy.algorithm();
}
public StrategyContext() {
}
public StrategyContext(Strategy strategy) {
this.strategy = strategy;
}
}
4.调用端测试
public class Test {
public static void main(String[] args) {
StrategyContext strategyContext = new StrategyContext(new StrategyA());
strategyContext.method();
}
}
运行结果
采用策略A计算
5.优化:将策略上下文换成策略工厂
public class StrategyFactory {
private static final StrategyFactory instance = new StrategyFactory();
private StrategyFactory() {
}
public static StrategyFactory getInstance(){
return instance;
}
private static Map<Integer,Strategy> map = new HashMap<>();
//通过类型获取策略
public Strategy getStrategy(Integer type){
if (type == null || !map.containsKey(type)){
throw new RuntimeException("策略不存在!");
}
return map.get(type);
}
//静态封装策略到map
static {
map.put(1,new StrategyA());
map.put(2,new StrategyB());
}
}
调用端测试
public class Test {
public static void main(String[] args) {
Strategy strategy = StrategyFactory.getInstance().getStrategy(2);
strategy.algorithm();
}
}
运行结果
采用策略B计算
可以将类型定义成枚举
public enum AlgorithmType {
/**
* A算法
*/
A(1,"A算法"),
/**
* B算法
*/
B(2,"B算法");
AlgorithmType(int type, String value) {
this.type = type;
this.value = value;
}
private int type;
private String value;
public int getType() {
return type;
}
public String getValue() {
return value;
}
}
6.优化:将策略上下文换成策略选择器
策略接口新增一个算法类型接口
public interface Strategy {
void algorithm();
Integer getAlgorithmType();
}
同时实现类也新增对应的类型方法
@Component
public class StrategyA implements Strategy {
@Override
public void algorithm() {
System.out.println("采用策略A计算");
}
@Override
public Integer getAlgorithmType() {
return AlgorithmType.A.getType();
}
}
@Component
public class StrategyB implements Strategy {
@Override
public void algorithm() {
System.out.println("采用策略B计算");
}
@Override
public Integer getAlgorithmType() {
return AlgorithmType.B.getType();
}
}
策略选择器定义
@Component
public class StrategySelector {
private static Map<Integer,Strategy> map = new HashMap<>();
//(required=true),表示注入的时候,该bean必须存在,否则就会注入失败。
@Autowired(required = false)
private void init(List<Strategy> strategies){
if (CollectionUtils.isEmpty(strategies)) {
return;
}
//将策略接口注入进map
map = strategies.stream().collect(Collectors.toMap(Strategy::getAlgorithmType, s -> s));
System.out.println("StrategyMap:"+JSON.toJSONString(map));
}
public void method(Integer type){
map.get(type).algorithm();
}
}
启动服务器控制台输出StrategyMap:{1:{"algorithmType":1},2:{"algorithmType":2}},说明策略接口已全部封装在map
调用端
public class Test {
@Resource
private StrategySelector strategySelector;
public void test() {
strategySelector.method(AlgorithmType.A.getType());
}
}
7.优化:将策略上下文换策略选择器,采用注解形式注入
定义算法类型注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Algorithm {
int value();
}
在策略实现接口上加入注解
@Algorithm(1)
@Component
public class StrategyA implements Strategy {
@Override
public void algorithm() {
System.out.println("采用策略A计算");
}
}
@Algorithm(2)
@Component
public class StrategyB implements Strategy {
@Override
public void algorithm() {
System.out.println("采用策略B计算");
}
}
策略选择器定义
@Component
public class StrategySelector {
private static Map<Integer, Strategy> map = new HashMap<>();
@Autowired(required = false)
private void init(List<Strategy> strategies) {
if (CollectionUtils.isEmpty(strategies)) {
return;
}
for (Strategy strategy : strategies) {
//取方法上的策略类型注解
Algorithm annotation = AnnotationUtils.findAnnotation(strategy.getClass(), Algorithm.class);
//将策略接口注入进map
map.put(annotation.value(), strategy);
}
System.out.println("StrategyMap:"+JSON.toJSONString(map));
}
public void method(Integer type){
map.get(type).algorithm();
}
}
调用端
public class Test {
@Resource
private StrategySelector strategySelector;
public void test(){
strategySelector.method(AlgorithmType.A.getType());
}
}