# 策略模式Strategy
# 一、概念
# 1、定义
定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化不会影响到使用算法的用户。
# 2、扩展
if else 的代码可以通过策略模式消除掉。
# 3、类型
行为型
# 4、适用场景
- 系统有很多类,而他们的区别仅仅在于他们的行为不同
 - 一个系统需要动态的在几种算法中选择一种
 
# 5、优点
- 满足开闭原则
 - 避免使用多重条件转移语句
 - 提高算法的保密性和安全性
 
# 6、缺点
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类
 - 产生很多策略类
 
# 7、相关设计模式
- 策略模式和工厂模式
 
工厂模式是创建型的设计模式,接受指令,创建符合要求的具体对象;策略模式是行为型的设计模式,接受已经创建好的对象,从而实现不同的行为
- 策略模式和状态模式
 
策略模式中客户端需要知道选择哪个策略;状态模式中客户端不需要关系具体的状态,这些状态会自动转换。在不同状态下,如果行为有差异,而且状态可以发生转换时,可以使用状态模式。如果某个行为存在多种实现方式,可以使用策略模式。
# 二、应用
在各个购物节的时候都有各种各样的促销,这里定义一个促销接口:
public interface PromotionStrategy {
    void doPromotion();
}
 2
3
4
分别有3个具体的实现:满减促销、立减促销和返现促销。
public class FullReductionPromotionStrategy implements PromotionStrategy{
    @Override
    public void doPromotion() {
        System.out.println("满减促销");
    }
}
 2
3
4
5
6
7
public class DirectReductionPromotionStrategy implements PromotionStrategy{
    @Override
    public void doPromotion() {
        System.out.println("立减促销");
    }
}
 2
3
4
5
6
7
public class ReturnCashPromotionStrategy implements PromotionStrategy{
    @Override
    public void doPromotion() {
        System.out.println("返现促销");
    }
}
 2
3
4
5
6
7
在新建一个活动,活动接受一个促销策略作为参数传入构造方法中:
public class PromotionActivity {
    private PromotionStrategy promotionStrategy;
    public PromotionActivity(PromotionStrategy promotionStrategy) {
        this.promotionStrategy = promotionStrategy;
    }
    public void executePromotionStrategy() {
        promotionStrategy.doPromotion();
    }
}
 2
3
4
5
6
7
8
9
10
11
12
此时的类图:

应用层:
public class Test {
    public static void main(String[] args) {
        PromotionActivity promotionActivity618 = new PromotionActivity(new DirectReductionPromotionStrategy());
        PromotionActivity promotionActivity1111 = new PromotionActivity(new ReturnCashPromotionStrategy());
        promotionActivity618.executePromotionStrategy();
        promotionActivity1111.executePromotionStrategy();
    }
}
 2
3
4
5
6
7
8
9
10
执行结果:
立减促销
返现促销
 2
如果此时需要一个新的策略也非常简单,直接新建一个策略,然后传入到具体的活动中即可。
实际应用中的代码可能会这么写:
public class Test {
    public static void main(String[] args) {
        PromotionActivity promotionActivity;
        String promotionKey = "FullReduction";
        if (StringUtils.equals(promotionKey, "FullReduction")) {
            promotionActivity = new PromotionActivity(new FullReductionPromotionStrategy());
        } else if (StringUtils.equals(promotionKey, "DirectReduction")) {
            promotionActivity = new PromotionActivity(new DirectReductionPromotionStrategy());
        } else {
            promotionActivity = new PromotionActivity(new ReturnCashPromotionStrategy());
        }
        promotionActivity.executePromotionStrategy();
    }
}
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
前端传过来一个条件,根据这个条件判断采用哪种促销,然后使用执行:
满减促销
 但是这么做,还是要写很多 if else 语句。那么如何消除掉这部分代码呢?
首先创建一个促销工厂:
public class PromotionStrategyFactory {
    private static Map<String, PromotionStrategy> PROMOTION_STRATEGY_MAP = new HashMap<>();
    static {
        PROMOTION_STRATEGY_MAP.put(PromotionKey.FULL_REDUCTION, new FullReductionPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.DIRECT_REDUCTION, new DirectReductionPromotionStrategy());
        PROMOTION_STRATEGY_MAP.put(PromotionKey.RETURN_CASH, new ReturnCashPromotionStrategy());
    }
    private static final PromotionStrategy EMPTY_PROMOTION_STRATEGY = new EmptyPromotionStrategy();
    private PromotionStrategyFactory() {
    }
    public static PromotionStrategy getPromotionStrategy(String promotionKey) {
        PromotionStrategy promotionStrategy = PROMOTION_STRATEGY_MAP.get(promotionKey);
        return promotionStrategy == null ? EMPTY_PROMOTION_STRATEGY : promotionStrategy;
    }
    private interface PromotionKey {
        String FULL_REDUCTION = "FullReduction";
        String DIRECT_REDUCTION = "DirectReduction";
        String RETURN_CASH = "ReturnCash";
    }
}
 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
当没有匹配到任何促销策略的时候,这里会返回一个空的促销策略。这个空的促销策略:
public class EmptyPromotionStrategy implements PromotionStrategy {
    @Override
    public void doPromotion() {
        System.out.println("无促销");
    }
}
 2
3
4
5
6
7
那么此时的应用层就是这样子的:
public class Test {
    public static void main(String[] args) {
        String promotionKey = "DirectReduction";
        PromotionActivity promotionActivity = new PromotionActivity(
                PromotionStrategyFactory.getPromotionStrategy(promotionKey));
        promotionActivity.executePromotionStrategy();
    }
}
 2
3
4
5
6
7
8
9
执行结果:
立减促销
 # 三、源码中的应用
# 1、Comparator
Comparator 比较器接口就相当于一个策略,它有2个方法需要实现:
    int compare(T o1, T o2);
    
    boolean equals(Object obj);
 2
3
那这个策略在哪里使用呢?
Arrays 类有这么一个方法:
    private static <T> void legacyMergeSort(T[] a, int fromIndex, int toIndex,
                                            Comparator<? super T> c) {
        T[] aux = copyOfRange(a, fromIndex, toIndex);
        if (c==null)
            mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
        else
            mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c);
    }
 2
3
4
5
6
7
8
它的最后一个参数就接收一个比较器,并且在按照这比较逻辑,在方法内部一步一步往下传。
# 2、TreeMap
TreeMap 有这样一个比较器的成员变量:
    private final Comparator<? super K> comparator;
 内部还将这个比较器进行了加工:
    final int compare(Object k1, Object k2) {
        return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2)
            : comparator.compare((K)k1, (K)k2);
    }
 2
3
4
# 3、Spring 中的 Resource
在 org.springframework.core.io 包中的 Resource 类,它的实现类例如 ClassPathResource、FileSystemResource、PathResource、UrlResource 等等。这个 Resource 接口就相当于一个策略的抽象,这些实现类就是具体的行为。
# 4、Spring 中的 InstantiationStrategy
InstantiationStrategy 这个接口是 Spring 在初始化 Bean 的时候的一个策略接口,具体的实现类是 SimpleInstantiationStrategy 和 CglibSubclassingInstantiationStrategy,SimpleInstantiationStrategy 在原来 InstantiationStrategy 接口中又新增了2个方法,并且它还是 CglibSubclassingInstantiationStrategy 的父类。