# 策略模式

策略模式在源代码中通常以`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);
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://yangsx95.gitbook.io/notes/computer-science/she-ji-mo-shi/ce-le-mo-shi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
