工作中常用的设计模式-策略模式

发布时间:2024-03-31

统计字数:1032 字

阅读时间:6 min read

工作中常用的设计模式-策略模式

策略模式

在我们的工作中,经常会遇到这样的情况:虽然输入的数据结构是一致的,但根据不同的条件需要执行不同的处理逻辑。

比如说,我们要开发一个简单的消息推送模块,需要将消息推送到飞书、钉钉、企业微信等不同的平台,而根据消息的 type 属性来区分平台。

最直接最简单的方法是使用 if else 来进行条件判断。

首先,我们定义一个推送平台的枚举:

java
enum PlatformEnum {
    LARK(1, "飞书"),
    DINGTALK(2, "钉钉"),
    WECOM(3, "企业微信");

    private final Integer code;
    private final String desc;

    // 构造函数、getter方法略...
}

这个枚举列举了三个平台:飞书、钉钉和企业微信。

接着,我们定义一个消息实体:

java
class Message {
    private Integer type; // 推送平台类型
    private String content; // 推送消息
    private String webhook; // 推送 webhook 地址

    // 构造函数、getter和setter方法略...
}

在这个实体中,我们简单地定义了三个属性:推送平台类型、消息文本和 webhook 地址。

然后,我们可以编写推送方法如下:

java
class StrategyDemo1 {

    public static void main(String[] args) {
        Message message = new Message();
        message.setType(PlatformEnum.LARK.getCode());
        message.setContent("这是一条消息");
        message.setWebhook("https://test.com");
        push(message);
    }

    public static void push(Message message) {
        if (message.getType().equals(PlatformEnum.LARK.getCode())) {
            System.out.println("构建body,发送到飞书");
        } else if (message.getType().equals(PlatformEnum.DINGTALK.getCode())) {
            System.out.println("构建body,发送到钉钉");
        } else if (message.getType().equals(PlatformEnum.WECOM.getCode())) {
            System.out.println("构建body,发送到企业微信");
        }
    }
}

运行结果为:构建body,发送到飞书

通过这简单的几行代码,我们实现了根据平台类型进行推送的功能。但是,如果我们需要新增推送平台,应该怎么做呢?

通常的做法是在枚举类中添加新的平台,然后修改 push 方法并添加新的 else if 分支。

然而,这种方式有一个问题,就是随着平台数量的增加,代码会变得越来越庞大且难以维护。

有没有一种方法可以在增加新平台时不影响到现有代码逻辑呢? 答案是肯定的!这就是策略模式的用武之地。

下面我们来看看如何用策略模式重构这段代码。

首先,我们需要创建一个接口,所有的推送策略类都必须实现该接口:

java
interface MessagePush {
    void push(Message message);
}

我们可以将这个接口看作是推送消息的标准格式,只要调用 push 方法就能推送消息。

然后,我们创建三个具体的推送策略类:LarkMessagePush、DingTalkMessagePush 和 WeComMessagePush,分别对应飞书、钉钉和企业微信的推送逻辑:

java
class LarkMessagePush implements MessagePush {
    @Override
    public void push(Message message) {
        System.out.println("LarkMessagePush 推送消息:" + message.getContent());
    }
}

// DingTalkMessagePush 和 WeComMessagePush 类似,此处省略...

接着,我们需要存储 type 参数和对应的策略类的映射关系,可以使用一个 map 来实现:

java
class StrategyDemo1 {
    private static Map<Integer, MessagePush> messagePushHandleMap = new HashMap<>();

    static {
        messagePushHandleMap.put(PlatformEnum.LARK.getCode(), new LarkMessagePush());
        messagePushHandleMap.put(PlatformEnum.DINGTALK.getCode(), new DingTalkMessagePush());
        messagePushHandleMap.put(PlatformEnum.WECOM.getCode(), new WeComMessagePush());
    }

    // main 方法略...
}

最后,我们只需在推送时根据 type 从 map 中获取对应的策略类,然后调用 push 方法即可:

java
class StrategyDemo1 {
    public static void main(String[] args) {
        Message message = new Message();
        message.setType(PlatformEnum.LARK.getCode());
        message.setContent("飞书消息");
        message.setWebhook("https://test.com");

        MessagePush messagePush = messagePushHandleMap.get(message.getType());
        if (messagePush == null) {
            throw new RuntimeException("不支持的推送平台");
        }
        messagePush.push(message);
    }
}

运行结果为:LarkMessagePush 推送消息:飞书消息

当我们需要新增新的推送平台时,只需以下几步:

  1. 创建新的平台推送策略类并实现 MessagePush 接口
  2. 将 type 和新平台的策略类存入映射 map

这样,我们就实现了固定的判断逻辑,而不需要再修改原有的代码。

优化建议

  1. 将 type 和新平台的策略类存入映射 map 的过程可以更加简洁。
  2. 推送到 webhook 的操作大部分平台都是通过 post 请求发送到指定的地址,我们可以考虑在策略模式中优化这个步骤。

下一篇文章就来说说如何来进行优化