策略模式Strategy,非常实用!!

前言

当我们写业务代码的时候,经常可以在工程里看到很多坨下面这样的if else代码。如果想把手机通知加进来,就要再加个else if,然后再里面写业务代码。这样的方式代码臃肿,难以维护,不易于扩展。那么有什么办法可以写出更优雅的代码呢?
image.png
所以我们引入策略模式来解决这个问题。废话不多说,先看代码。
image.png

策略工厂

通知策略工厂,用于获取具体通知策略Bean对象,比如短信通知策略对象/邮件通知策略对象/微信通知策略对象。因为大多数我们使用Spring进行管理Bean,所以我们可以把通知方式和Bean对象维护在一个Map中。

/**
 * @author ZhangYao
 * @description NoticeFactory
 * @date Create in 16:04 2023/5/23
 */
@Service
public class NoticeFactory {
    /**
     * 存储通知方式和策略Bean关系
     */
    public static Map<String, NoticeStrategy> NOTICE_STRATEGY_MAP = new HashMap<>();

    /**
     * 注册策略Bean
     */
    public static void registerBean(String noticeType, NoticeStrategy noticeStrategy) {
        NOTICE_STRATEGY_MAP.put(noticeType, noticeStrategy);
    }

    /**
     * 获取策略Bean
     */
    public NoticeStrategy getInstance(String noticeType) {
        NoticeStrategy strategy = NOTICE_STRATEGY_MAP.get(noticeType);
        if (strategy == null) {
            strategy = NOTICE_STRATEGY_MAP.get(CoreConstants.NoticeType.DEFAULT);
        }
        return strategy;
    }
}

策略接口

通知策略接口,目前只有一个发送消息的接口方法。

public interface NoticeStrategy {
    default String sendMessage(String message) {
        return "send message(" + message + ") successful.";
    }
}

抽象策略类

抽象策略类,实现了通知策略接口和InitializingBean接口,InitializingBean接口用于Spring在创建Bean的流程中存储通知方式和策略Bean关系Map。

/**
 * @author ZhangYao
 * @description 通知抽象类
 * @date Create in 11:38 2023/5/29
 */
public abstract class AbstractNoticeStrategyImpl implements NoticeStrategy, InitializingBean {
}

消息实体类

也就是入参对象封装,其中最重要的就是通知类型noticeType,其他字段都属于业务字段,比如消息内容,用户Id等等。

/**
 * @author ZhangYao
 * @description 消息实体类
 * @date Create in 13:57 2023/5/29
 */
public class MessageEntity {
    /**
     * 通知类型:sms;email;weChat;
     */
    private String noticeType;
    /**
     * 通知内容
     */
    private String content;

    /**
     * 用户Id
     */
    private String userId;

    // ...

    public String getNoticeType() {
        return noticeType;
    }

    public void setNoticeType(String noticeType) {
        this.noticeType = noticeType;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }
}

上下文 Context

用于提供给其他调用方直接调用,符合开闭原则

/**
 * @author ZhangYao
 * @description NoticeContext
 * @date Create in 14:17 2023/5/23
 */
@Component
public class NoticeContext {
    @Autowired
    private NoticeFactory noticeFactory;

    public String sendMessage(MessageEntity message) {
        NoticeStrategy noticeStrategy = noticeFactory.getInstance(message.getNoticeType());
        return noticeStrategy.sendMessage(message.getContent());
    }
}

具体策略接口实现类

短信通知实现类

/**
 * @author ZhangYao
 * @description 短信通知实现类
 * @date Create in 15:06 2023/5/23
 */
@Service
public class SmsNoticeStrategyImpl extends AbstractNoticeStrategyImpl {
    /**
     * 项目启动时,初始化当前类的Bean时调用
     */
    @Override
    public void afterPropertiesSet() {
        NoticeFactory.registerBean(CoreConstants.NoticeType.SMS, this);
    }

    @Override
    public String sendMessage(String message) {
        return "send sms message(" + message + ") successful.";
    }
}

邮件通知实现类

/**
 * @author ZhangYao
 * @description 邮件通知实现类
 * @date Create in 11:34 2023/5/29
 */
@Service
public class EmailNoticeStrategyImpl extends AbstractNoticeStrategyImpl {
    @Override
    public void afterPropertiesSet() {
        NoticeFactory.registerBean(CoreConstants.NoticeType.EMAIL, this);
    }

    @Override
    public String sendMessage(String message) {
        return "send email message(" + message + ") successful.";
    }
}

微信通知实现类

/**
 * @author ZhangYao
 * @description 微信通知实现类
 * @date Create in 11:34 2023/5/29
 */
@Service
public class WeChatNoticeStrategyImpl extends AbstractNoticeStrategyImpl {
    @Override
    public void afterPropertiesSet() {
        NoticeFactory.registerBean(CoreConstants.NoticeType.WE_CHAT, this);
    }

    @Override
    public String sendMessage(String message) {
        return "send weChat message(" + message + ") successful.";
    }
}

其他的策略实现就不贴出来了,道理都是一样的。
是在策略类Bean初始化时,把Bean放在工厂类的 Map。这样的好处是不需要单独维护Bean和noticeType的关系。
以后我们新增一个通知策略,比如 QQ 通知用户,只需要新增一个 QQNoticeStrategy 类即可,然后在这个类里指定具体的 noticeType 即可。

测试控制器

比如controller层需要调发送消息接口,直接调noticeContext的sendMessage方法。

@Controller
@RequestMapping("/notice")
public class NoticeController {
    @Autowired
    private NoticeContext noticeContext;
    /**
     curl --location --request POST 'localhost:8080/notice/send-message' \
     --header 'Content-Type: application/json' \
     --data-raw '{
     "noticeType": "sms",
     "content": "hi,boy!"
     }'
     */
    @ResponseBody
    @PostMapping("/send-message")
    public String sendMessage(@RequestBody CommonMessage message) {
        if (message == null) {
            message.setNoticeType(CoreConstants.NoticeType.SMS);
            message.setContent("hello word!");
        }
        return noticeContext.sendMessage(message);
    }
}

使用postman测试我们刚刚写的策略模式代码。当然我更推荐你使用单元测试。
image.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

耀耀zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值