# 策略模式

策略模式在源代码中通常以`Strategy`、`Policy`、`Handler`结尾，其中大多数以后2者为多，比如在JUC中，创建`ThreadPoolExecutor`对象需要一个`RejectedExecutionHandler`对象，该接口就是典型的策略模式接口。他有几个子类，比如`DiscardOldestPolicy`、`AbortPolicy`等。

## 应用场景：JUC

1. 创建`ThreadPoolExecutor`对象需要一个`RejectedExecutionHandler`对象，改接口就是一种策略模式，拥有不同的实现，每个实现都代表着一种不同的拒绝策略。

## 策略工厂消除ifelse

### Spring策略工厂方式一

相关设计模式：

1. 策略
2. 工厂
3. 享元
4. spring Bean生命周期方法
5. 模板方法

消息类型枚举，是判别策略的维度：

```java
public enum MessageType {

    TYPE_A, 
    TYPE_B, 
    TYPE_C,
    ;
}
```

策略接口 `MqSenderStrategy`，实现Spring生命周期方法，用于在初始化后注册策略实现到Factory中：

```java
public interface MqSenderStrategy extends InitializingBean{

    void send(String message);

}
```

抽象策略，可以引入模板方法模式，实现公共的业务逻辑：

```java
public abstract class AbstractMqSenderStrategy implements MqSenderStrategy {

    protected abstract MessageType getMessageType();

    // 使用生命周期方法注册到工厂类中
    // 也可以使用@PostConstuct
    @Override
    public void afterPropertiesSet() throws Exception {
        MqSenderStrategyFactory.registrySender(getMessageType(), this);
    }
        
    /**
     * 发送模板代码封装
     */
    @Override
    public void send(String message) {
        // Connection c = new Connection(); 创建连接
        // c.connect()
        doSend(message);
        // c.disconnect(); 断开连接
    }

    protected abstract void doSend(String message);
        
}
```

策略实现：

```java
@Component
public class ASenderStrategy extends AbstractMqSenderStrategy {

    @Override
    protected MessageType getMessageType() {
        return MessageType.TYPE_A;
    }
        
    @Override
    public void doSend(String message) {
    }

}
```

工厂类：

```java
public class MqSenderStrategyFactory {
        
    private static final ConcurrentHashMap<MessageType, MqSenderStrategy> SENDER_MAP;
        
    static {
        SENDER_MAP = new ConcurrentHashMap<>(MessageType.values().length);
    }
        
    public static void registrySender(MessageType messageType, MqSenderStrategy     mqSenderStrategy) {
        if (messageType == null) {
            throw new RuntimeException("注册Sender到Factory失败，消息类型不可为null");
        }
        
        if (SENDER_MAP.get(messageType) != null) {
            throw new RuntimeException("相同类型的消息处理策略只能注册到Factory一次");
        }
        
        SENDER_MAP.put(messageType, mqSenderStrategy);
    }
    
    public static MqSenderStrategy getSender(MessageType messageType) {
        return SENDER_MAP.get(messageType);
    }
}
```

### Spring策略工厂方式二

与方式一相比：

1. Factory类加入Spring IoC
2. 策略类使用Autowrid机制自动加入到Factory中，而不是通过生命周期钩子主动注入，策略类更简洁，与Factory耦合更小
3. 使用List存储策略实现类，然后可以通过`@Order`注解控制策略实现类的优先级（当策略选择条件复杂时，有可能多个策略同时满足，这个可以通过优先级处理）

策略接口不需要集成生命周期函数，需要暴露getMessageType方法供工厂类使用 ：

```java
public interface MqSenderStrategy {

    MessageType getMessageType();

    void send(String message);

}
```

策略实现：

```java
@Component
@Order(1)
@Lazy
public class ASenderStrategy extends AbstractMqSenderStrategy {

    @Override
    protected MessageType getMessageType() {
        return MessageType.TYPE_A;
    }
        
    @Override
    public void doSend(String message) {
    }

}
```

策略工厂加入IoC，并且注入所有实现进入：

```java
public class MqSenderStrategyFactory {

    @Autowried
    private List<MqSenderStrategy> sendList;
        
    private static final ConcurrentHashMap<MessageType, MqSenderStrategy> SENDER_MAP; 
        
    static {
        SENDER_MAP = new ConcurrentHashMap<>(MessageType.values().length);
    }
        
    // 工厂对象创建完毕，初始化策略工厂
    @PostConstruct
    public void registrStrategy() {
        sendList.forEach(e - > SENDER_MAP.put(e.getMessageType()));
    }
    
    public static MqSenderStrategy getSender(MessageType messageType) {
        return SENDER_MAP.get(messageType);
    }
}
```
