设计模式之策略模式

策略模式

  • 一、准备工作
  • 二、方式一
  • 三、方式二
  • 三、方式三
    • 3.1、策略模式接口
    • 3.2、策略模式文本实现
    • 3.3、策略模式图片实现
    • 3.4、使用策略模式

一、准备工作

消息类型枚举

/**
 * 微信消息类型枚举
 * 开发文档: https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html
 *
 * @Author [email protected]
 * @Date 2023/3/24 15:59
 */
@Getter
@AllArgsConstructor
public enum WechatMessageTypeEnum {
    TEXT("text", "文本消息"),
    IMAGE("image", "图片消息"),
    VOICE("voice", "语音消息"),
    VIDEO("video", "视频消息"),
    MUSIC("music", "音乐消息"),
    SHORT_VIDEO("shortvideo", "小视频消息"),
    LOCATION("location", "地理位置消息"),
    LINK("link", "链接消息"),
    EVENT("event", "链接消息");

    /**
     * 消息类型
     */
    private final String type;

    /**
     * 消息名称
     */
    private final String name;

    /**
     * 获取所有的消息类型集合
     *
     * @param
     * @return List
     */
    public static List<String> getMessageTypeList() {
        return Arrays.asList(
                TEXT.getType(),
                IMAGE.getType(),
                VOICE.getType(),
                VIDEO.getType(),
                MUSIC.getType(),
                SHORT_VIDEO.getType(),
                LOCATION.getType(),
                LINK.getType(),
                EVENT.getType()
        );
    }
}

二、方式一


private static Map<String, Class> MESSAGE_HANDLER_MAP = new HashMap<>();

@PostConstruct
public void initMessageHander() {
    MESSAGE_HANDLER_MAP.put(WechatMessageTypeEnum.TEXT.getType(), TextMessage.class);
    MESSAGE_HANDLER_MAP.put(WechatMessageTypeEnum.IMAGE.getType(), ImageMessage.class);
}

/**
 * 微信请求的基础消息处理统一入口-方式一
 *
 * @param request 微信请求消息
 * @return String
 */
public String messageHandle(WechatMessageRequest request) {
    log.info("======>[WechatMessageHandler::messageHandle] 接收到微信请求消息: {}", request);

    // 检查消息类型
    List<String> msgTypeList = WechatMessageTypeEnum.getMessageTypeList();
    if (!msgTypeList.contains(request.getMsgType())) {
        log.warn("======>[WechatMessageHandler::messageHandle] 无法处理的事件消息: {}", request);
        return WechatReturnContentEnum.SUCCESS.getContent();
    }

    Assert.isTrue(msgTypeList.contains(request.getMsgType()), "无法处理的消息类型:" + request.getMsgType());

    try {
        // 获取Method
        Class aClass = MESSAGE_HANDLER_MAP.get(request.getMsgType());
        Method method = this.getClass().getDeclaredMethod("allTypeMessageHandle", aClass);
        method.setAccessible(true);

        // 拷贝
        ConverterRegistry converterRegistry = ConverterRegistry.getInstance();
        Object convert = converterRegistry.convert(aClass, request);

        // 反射
        Object result = method.invoke(this, convert);
        return  Convert.toStr(result, WechatReturnContentEnum.SUCCESS.getContent());
    } catch (Exception e) {
        log.error("消息处理失败, 失败原因:{}", e.getMessage());
    }
    return WechatReturnContentEnum.SUCCESS.getContent();
}

/**
 * 处理微信请求的图片消息
 *
 * @param imageMessage 微信请求的图片消息
 * @return String
 */
private String allTypeMessageHandle(ImageMessage imageMessage) {
    // TODO: 业务逻辑
    return WechatReturnContentEnum.SUCCESS.getContent();
}

/**
 * 处理微信请求的文本消息
 *
 * @param textMessage 微信请求的文本消息
 * @return String
 */
private String allTypeMessageHandle(TextMessage textMessage) {
    // TODO: 业务逻辑
    return WechatReturnContentEnum.SUCCESS.getContent();
}

三、方式二

private static Map<String, MessageRoute> MESSAGE_HANDLER_ROUTE_MAP = new HashMap<>();

@PostConstruct
public void initMessageHanderRounte() {
    MESSAGE_HANDLER_ROUTE_MAP.put(WechatMessageTypeEnum.TEXT.getType(), new MessageRoute<TextMessage>(this::textHandle, new TextMessage()));
    MESSAGE_HANDLER_ROUTE_MAP.put(WechatMessageTypeEnum.IMAGE.getType(), new MessageRoute<ImageMessage>(this::imageHandle, new ImageMessage()));
}

/**
 * 微信请求的基础消息处理统一入口-方式二
 *
 * @param request
 * @return String
 */
public String messageRounteHandle(WechatMessageRequest request) {
    log.info("======>[WechatMessageHandler::messageHandle] 接收到微信请求消息: {}", request);

    // 检查消息类型
    List<String> msgTypeList = WechatMessageTypeEnum.getMessageTypeList();
    if (!msgTypeList.contains(request.getMsgType())) {
        log.warn("======>[WechatMessageHandler::messageHandle] 无法处理的事件消息: {}", request);
        return "success";
    }

    // 获取消息路由
    MessageRoute messageRoute = MESSAGE_HANDLER_ROUTE_MAP.get(request.getMsgType());

    // 拷贝
    BeanUtils.copyProperties(request, messageRoute.getObj());

    // 调用
    Object result = messageRoute.getFunction().apply(messageRoute.getObj());

    // 结果处理
    return Convert.toStr(result, WechatReturnContentEnum.SUCCESS.getContent());
}

/**
 * 图片消息处理
 *
 * @param imageMessage 请求的图片消息
 * @return String
 */
private String imageHandle(ImageMessage imageMessage) {
    // TODO: 业务逻辑
    return WechatReturnContentEnum.SUCCESS.getContent();
}

/**
 * 文本消息处理
 *
 * @param textMessage 请求的文本消息
 * @return String
 */
private String textHandle(TextMessage textMessage) {
    // TODO: 业务逻辑
    return WechatReturnContentEnum.SUCCESS.getContent();
}

三、方式三

以上代码,违背了面向对象编程的开闭原则以及单一原则。

  • 开闭原则(对于扩展是开放的,但是对于修改是封闭的):增加或者删除某个逻辑,都需要修改到原来代码
  • 单一原则(规定一个类应该只有一个发生变化的原因):修改任何类型的分支逻辑代码,都需要改动当前类的代码。

3.1、策略模式接口

/**
 * 策略模式接口
 *
 * @Author [email protected]
 * @Date 2023/3/27 17:10
 */
public interface WechatMessageStrategy<T> {
    /**
     * 获取消息类型
     *
     * @return String
     */
    String getMessageType();

    /**
     * 获取调用方法参数对象
     *
     * @param request 微信请求参数
     * @return T
     */
    T getParam(WechatMessageRequest request);

    /**
     * 封装的公用算法(具体的处理消息方法)
     *
     * @param message
     * @return String
     */
    String handleMessage(T message);
}

3.2、策略模式文本实现

/**
 * 微信推送文本消息处理策略
 *
 * @Author [email protected]
 * @Date 2023/3/27 17:14
 */
@Slf4j
@Component
public class WechatTextMessageStrategy implements WechatMessageStrategy<TextMessage> {
    /**
     * 获取消息类型
     *
     * @return String
     */
    @Override
    public String getMessageType() {
        return WechatMessageTypeEnum.TEXT.getType();
    }


    /**
     * 获取调用方法参数对象
     *
     * @param request 微信请求参数
     * @return TextMessage
     */
    @Override
    public TextMessage getParam(WechatMessageRequest request) {
        TextMessage textMessage = new TextMessage();
        BeanUtils.copyProperties(request, textMessage);
        return textMessage;
    }

    /**
     * 处理微信请求的文本消息
     *
     * @param message 微信请求的文本消息
     * @return String
     */
    @Override
    public String handleMessage(TextMessage message) {
        log.info("处理[{}], 消息内容:{}", WechatMessageTypeEnum.TEXT.getName(), message);
        return WechatReturnContentEnum.SUCCESS.getContent();
    }
}

3.3、策略模式图片实现

/**
 * 微信推送图片消息处理策略
 *
 * @Author [email protected]
 * @Date 2023/3/27 17:14
 */
@Slf4j
@Component
public class WechatImageMessageStrategy implements WechatMessageStrategy<ImageMessage> {

    /**
     * 获取消息类型
     *
     * @return String
     */
    @Override
    public String getMessageType() {
        return WechatMessageTypeEnum.IMAGE.getType();
    }


    /**
     * 获取调用方法参数对象
     *
     * @param request 微信请求参数
     * @return ImageMessage
     */
    @Override
    public ImageMessage getParam(WechatMessageRequest request) {
        ImageMessage imageMessage = new ImageMessage();
        BeanUtils.copyProperties(request, imageMessage);
        return imageMessage;
    }

    /**
     * 处理微信请求的图片消息
     *
     * @param message 微信请求的图片消息
     * @return String
     */
    @Override
    public String handleMessage(ImageMessage message) {
        log.info("处理[{}], 消息内容:{}", WechatMessageTypeEnum.IMAGE.getName(), message);
        return WechatReturnContentEnum.SUCCESS.getContent();
    }
}

3.4、使用策略模式

借助spring的生命周期,使用ApplicationContextAware接口,把对用的策略,初始化到map里面。然后对外提供resolveMessage方法即可。

/**
 * 使用策略模式处理微信请求消息
 *
 * @Author [email protected]
 * @Date 2023/3/27 17:09
 */
@Slf4j
@Component
public class WechatMessageAware implements ApplicationContextAware {
    /**
     * 消息类型策略
     */
    private Map<String, WechatMessageStrategy> msgTypeMap = new ConcurrentHashMap<>();

    /**
     * 解析消息
     *
     * @param request 微信消息请求参数
     * @return String
     */
    public String resolveMessage(WechatMessageRequest request) {
        // 获取微信消息策略
        WechatMessageStrategy wechatMessageTypeStrategy = msgTypeMap.get(request.getMsgType());

        // 判断是否存在该策略
        if (wechatMessageTypeStrategy == null) {
            log.error("消息策略不存在, 消息类型:{}, 请求参数:{}", request.getMsgType(), request);
            return WechatReturnContentEnum.SUCCESS.getContent();
        }

        // 返回数据
        return wechatMessageTypeStrategy.handleMessage(wechatMessageTypeStrategy.getParam(request));
    }

    /**
     * 把不同策略放到map
     *
     * @param applicationContext 应用上下文对象
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        // 获取接口下所有实现类
        Map<String, WechatMessageStrategy> beansOfTypeMap = applicationContext.getBeansOfType(WechatMessageStrategy.class);

        // 将所有的实现类添加到msgTypeMap中
        this.msgTypeMap = beansOfTypeMap.values()
                .stream()
                .collect(Collectors.toMap(e -> e.getMessageType(), e -> e));

    }
}

你可能感兴趣的:(设计模式,策略模式,设计模式,java,设计规范)