设计模式实战之策略模式

1,257 阅读2分钟

概念

接口提供抽象策略方法,由实现类提供具体的策略,并在使用时能整体替换。

  • Strategy 策略接口
  • ConcreteStrategy 具体策略实现类
  • Context 上下文 用来选择具体策略

适用场景

  • 根据不同业务类型选择不同的处理器来处理
  • 替换大量if else

优点

  • 策略之间可以随意切换
  • 添加新策略只需要新建类,不需要修改原有代码

缺点

  • 当策略比较多时,也需要较多的实现类

实战

根据不能消息类型来选择不能的消息处理器

  • 消息实体类
@Data
public class Message {
    private String type;
    private String content;
}
  • 消息处理接口 策略接口
public interface IMessageHandler {
    
    /**
     * 消息处理
     * @param message msg
     */
    void handle(Message message) throws Exception;
    
    /**
     * 支持处理的消息类型 text、image 等
     * @return string
     */
    String support();
}
  • 纯文本消息处理器 具体策略
/**
 * 纯文本消息处理器
 * @author xup
 * @date 2019/11/12 19:00
 */
@Component
public class TextMessageHandler implements IMessageHandler {
    
    @Override
    public void handle(Message message) {
        System.out.println("处理纯文本消息");
    }
    
    @Override
    public String support() {
        return "Text";
    }
}
  • 图片消息处理器 具体策略
/**
 * 图片消息处理器
 * @author xup
 * @date 2019/11/12 19:01
 */
@Component
public class ImageMessageHandler implements IMessageHandler {
   
    @Override
    public void handle(Message message) {
        System.out.println("处理纯文本消息");
    }
    
    @Override
    public String support() {
        return "Image";
    }
}
  • 消息处理器路由类 策略路由类
/**
 * 消息处理器路由类
 * 只进行路由,不进行消息处理
 * @author xup
 * @date 2019/11/12 19:06
 */
@Order(1)
@Component
public class MessageHandlerRoute implements IMessageHandler{
    /**
    * 业务类型和业务处理器存放的容器
     */
    private Map<String, IMessageHandler> messageHandlerMap = new HashMap<>(8);
    
    /**
     * 初始化类是 将IMessageHandler的所有实现类放入map容器
     */
    @PostConstruct
    public void init(){
        Map<String, IMessageHandler> beanMap = SpringContextHolder.getBeansOfType(IMessageHandler.class);
        for (IMessageHandler handler : beanMap.values()) {
            messageHandlerMap.put(handler.support(), handler);
        }
    }
    
    /**
     * 根据消息类型路由到不同的处理器
     * @param message msg
     * @return IMessageHandler
     */
    public IMessageHandler route(Message message) throws Exception {
        IMessageHandler handler = messageHandlerMap.get(message.getType());
        if (handler == null){
            throw new Exception("此消息类型没有配置处理器");
        }
        return handler;
    }
    
    @Override
    public void handle(Message message) throws Exception {
        IMessageHandler handler = route(message);
        handler.handle(message);
    }
    
    @Override
    public String support() {
        return "null";
    }
}

路由类可不实现策略接口。 可通过注入路由类,然后路由到具体的处理器再进行处理

IMessageHandler handler =  messageHandlerRoute.route(message)

handler.handle(message)
  • spring 上下文持有类
/**
 * spring 上下文持有类
 *
 * @author xup
 * @date 2019/11/12 17:45
 */
@Component
public class SpringContextHolder implements ApplicationContextAware {
    private static ApplicationContext applicationContext = null;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextHolder.applicationContext = applicationContext;
    }
    
    /**
     * 获取ApplicationContext.
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }
    
    /**
     * 从applicationContext中得到Bean, 自动转型为所赋值对象的类型.
     */
    public static <T> T getBean(Class<T> requiredType) {
        return applicationContext.getBean(requiredType);
    }
    
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanName) {
        return (T)applicationContext.getBean(beanName);
    }
    
    /**
     * 获取spring 容器中所有指定类型的Bean
     * @param type class
     * @return map
     */
    public static <T> Map<String, T> getBeansOfType(Class<T> type) {
        return applicationContext.getBeansOfType(type);
    }
}
  • 实际调用
@Autowired
IMessageHandler messageHander;

messageHandler.hander(message);