在公司的项目中,在某些场景使用设计模式来完成自己的需求,很能体现一个人的代码水平。
本文介绍策略模式,在 Spring 项目(或SpringBoot) 中引入策略模式来解决一个通过不同的方式通知用户的场景。
比如用户注册、忘记密码或其他推送信息,我们需要给用户发送信息,可以通过电子邮件、电话、微信、短信等方式通知用户。
比较 low 的代码如下:
public void notice(String noticeWay, String userId) {
if ("EMAIL".equals(noticeWay)) {
// TODO 通过电子邮件通知用户具体逻辑
System.out.println("通过电子邮件通知用户具体逻辑");
} else if ("PHONE".equals(noticeWay)) {
// TODO 通过电话通知用户具体逻辑
System.out.println("通过电话通知用户具体逻辑");
} else if ("SMS".equals(noticeWay)) {
// TODO 通过短信通知用户具体逻辑
System.out.println("通过短信通知用户具体逻辑");
} else if ("WECHAT".equals(noticeWay)) {
// TODO 通过微信通知用户具体逻辑
System.out.println("通过微信通知用户具体逻辑");
}
// ...
}
这样的代码,每新增一个通知策略,需要加一个 else if,然后再里面写具体的逻辑。
代码显得很臃肿,难以维护,不易于扩展。
然后,我们开始介绍使用策略模式来解决这个问题。
废话不多说,直接上代码
代码如下
1、策略工厂
通知策略工厂,用于获取具体通知策略Bean对象,比如微信通知策略对象,邮件策略通知对象
因为我们使用 Spring 管理Bean,所以我们可以把通知方式和Bean对象维护在一个 Map 里
package com.liuyanzhao.sens.demo.factory;
import com.liuyanzhao.sens.demo.strategey.NoticeStrategy;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* 通知策略工厂
*
* @author 言曌
* @date 2020/8/28 12:17 上午
*/
@Service
public class NoticeStrategyFactory {
/**
* 存储通知方式和策略Bean关系
*/
public static Map<String, NoticeStrategy> STRATEGY_MAP = new HashMap<>();
/**
* 注册策略Bean
*
* @param noticeWay 通知方式
* @param noticeStrategy 策略Bean
*/
public static void registerBean(String noticeWay, NoticeStrategy noticeStrategy) {
STRATEGY_MAP.put(noticeWay, noticeStrategy);
}
/**
* 获取策略Bean
*
* @param noticeWay 通知方式
* @return
*/
public NoticeStrategy getNoticeStrategyBean(String noticeWay) {
return STRATEGY_MAP.get(noticeWay);
}
}
2、策略接口
通知策略接口,目前只有一个通知接口方法
package com.liuyanzhao.sens.demo.strategey;
import com.liuyanzhao.sens.demo.dto.NoticeStrategyDTO;
/**
* @author 言曌
* @date 2020/8/28 12:20 上午
*/
public interface NoticeStrategy {
/**
* 通知用户
*
* @param strategyDTO
*/
void notice(NoticeStrategyDTO strategyDTO);
}
3、策略DTO
即入参对象封装,里面很重要的属性就是通知方式 noticeWay ,其他字段属于业务字段
package com.liuyanzhao.sens.demo.dto;
import lombok.Data;
/**
* 通知策略DTO
* @author 言曌
* @date 2020/8/28 12:21 上午
*/
@Data
public class NoticeStrategyDTO {
/**
* 通知方式: EMAIL、SMS、PHONE、WECHAT
*/
private String noticeWay;
/**
* 用户ID
*/
private String userId;
// other
}
4、上下文 Context
用于提供给调用方直接调用,符合开闭原则
即其他代码,如 controller 层需要调用通知用户 notice 方法,直接调用 Context 类的 notice 方法
package com.liuyanzhao.sens.demo.context;
import com.liuyanzhao.sens.demo.dto.NoticeStrategyDTO;
import com.liuyanzhao.sens.demo.strategey.NoticeStrategy;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author 言曌
* @date 2020/8/28 12:40 上午
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NoticeStrategyContext {
/**
* 注入策略类:通过构造器方式
*/
private NoticeStrategy noticeStrategy;
/**
* 通知方法
*
* @param strategyDTO
*/
public void notice(NoticeStrategyDTO strategyDTO) {
noticeStrategy.notice(strategyDTO);
}
}
5、具体的策略实现
(1)电子邮件通知策略
package com.liuyanzhao.sens.demo.strategey;
import com.liuyanzhao.sens.demo.dto.NoticeStrategyDTO;
import com.liuyanzhao.sens.demo.factory.NoticeStrategyFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
/**
* 电子邮件通知策略
*
* @author 言曌
* @date 2020/8/28 12:24 上午
*/
@Service
public class EmailNoticeStrategy implements NoticeStrategy, InitializingBean {
private static final String noticeWay = "EMAIL";
/**
* 项目启动时,初始化当前类的Bean时调用
*/
@Override
public void afterPropertiesSet() {
NoticeStrategyFactory.registerBean(noticeWay, this);
}
@Override
public void notice(NoticeStrategyDTO strategyDTO) {
// TODO 通过电子邮件通知用户具体逻辑
System.out.println("通过电子邮件通知用户具体逻辑");
}
}
(2)微信通知策略
package com.liuyanzhao.sens.demo.strategey;
import com.liuyanzhao.sens.demo.dto.NoticeStrategyDTO;
import com.liuyanzhao.sens.demo.factory.NoticeStrategyFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
/**
* 微信通知策略
*
* @author 言曌
* @date 2020/8/28 12:25 上午
*/
@Service
public class WechatNoticeStrategy implements NoticeStrategy, InitializingBean {
private static final String noticeWay = "WECHAT";
/**
* 项目启动时,初始化当前类的Bean时调用
*/
@Override
public void afterPropertiesSet() {
NoticeStrategyFactory.registerBean(noticeWay, this);
}
@Override
public void notice(NoticeStrategyDTO strategyDTO) {
// TODO 通过微信通知用户具体逻辑
System.out.println("通过微信通知用户具体逻辑");
}
}
其他的策略没必要贴了,道理都是一样的,需要在策略类Bean初始化时,将Bean放到工厂类的 Map 里即可
这样的好处是不需要单独维护 Bean 和 noticeWay 的关系
以后我们新增一个通知策略,比如 QQ 通知用户,只需要新增一个 QQNoticeStrategy 类即可,然后在这个类里指定具体的 noticeWay 即可
您可以选择一种方式赞助本站
支付宝扫一扫赞助
微信钱包扫描赞助
赏