从业多年,也算是用上了设计模式。分享记录一下最近实际项目中采用设计模式的技术方案。大佬轻喷,我就是想记录一下。
背景
项目需要对接多家三方渠道进行入会和退会操作。各个平台渠道的数据分表存储,核心流程基本一致,但三方渠道的参数及相关逻辑存在差异。以下以解绑操作为例,分别采用策略模式、工厂模式和策略+工厂模式实现。
1. 策略模式
定义策略接口
public interface PlatformStrategy {
void unBind(UserInfo userInfo);
UserInfo getUserInfo(Long id);
PlatformChannelEnum getPlatformEnum();
}
具体策略 - A平台
@Service
public class PlatformAStrategyImpl implements PlatformStrategy {
@Resource
private PlatformAMapper aMapper;
@Override
public void unBind(UserInfo userInfo) {
// A平台的解绑逻辑
System.out.println("解绑A平台用户,用户ID:" + userInfo.getId());
}
@Override
public UserInfo getUserInfo(Long id) {
// 获取A平台用户信息的逻辑
System.out.println("获取A平台用户信息的逻辑,用户ID:" + id);
UserInfo userInfo = new UserInfo();
return userInfo;
}
@Override
public PlatformChannelEnum getPlatformEnum() {
// 平台标识 -- A
return PlatformChannelEnum.A;
}
}
具体策略 - B平台
@Service
public class PlatformBStrategyImpl implements PlatformStrategy {
@Resource
private PlatformBMapper bMapper;
@Override
public void unBind(UserInfo userInfo) {
// B平台的解绑逻辑
System.out.println("解绑B平台用户,用户ID:" + userInfo.getId());
}
@Override
public UserInfo getUserInfo(Long id) {
// 获取B平台用户信息的逻辑
System.out.println("获取B平台用户信息的逻辑,用户ID:" + id);
UserInfo userInfo = new UserInfo();
return userInfo;
}
@Override
public PlatformChannelEnum getPlatformEnum() {
// 平台标识 -- B
return PlatformChannelEnum.B;
}
}
Service 层实现
@Service
public class UserPlatformServiceImpl implements UserPlatformService {
@Autowired
private PlatformAStrategyImpl aStrategy;
@Autowired
private PlatformBStrategyImpl bStrategy;
@Override
public void userUnbind(String uid, UnbindReq request) {
String platform = request.getPlatform();
Long id = request.getId();
PlatformStrategy strategy = null;
// 根据传递的参数来决定使用哪个策略
if ("A".equals(platform)) {
strategy = aStrategy;
} else if ("B".equals(platform)) {
strategy = bStrategy;
} else {
throw new ReturnException(ReturnEnum.UNKNOWN_PLATFORM_ERROR);
}
UserInfo userInfo = strategy.getUserInfo(id);
strategy.unBind(userInfo);
}
}
优点
- 逻辑简单,易于理解:直接使用策略接口,实现清晰。
缺点
- 耦合度较高:需要知道所有策略类的名称,客户端与策略类耦合度较高。
2. 工厂模式
定义平台接口
public interface PlatformService {
void unBind(UserInfo userInfo);
UserInfo getUserInfo(Long id);
PlatformChannelEnum getPlatformEnum();
}
A平台实现
@Service
public class PlatformAStrategyImpl implements PlatformService {
@Resource
private PlatformAMapper aMapper;
@Override
public void unBind(UserInfo userInfo) {
// A平台的解绑逻辑
System.out.println("解绑A平台用户,用户ID:" + userInfo.getId());
}
@Override
public UserInfo getUserInfo(Long id) {
// 获取A平台用户信息的逻辑
System.out.println("获取A平台用户信息的逻辑,用户ID:" + id);
UserInfo userInfo = new UserInfo();
return userInfo;
}
@Override
public PlatformChannelEnum getPlatformEnum() {
// 平台标识 -- A
return PlatformChannelEnum.A;
}
}
B平台实现
@Service
public class PlatformBStrategyImpl implements PlatformService {
@Resource
private PlatformBMapper bMapper;
@Override
public void unBind(UserInfo userInfo) {
// B平台的解绑逻辑
System.out.println("解绑B平台用户,用户ID:" + userInfo.getId());
}
@Override
public UserInfo getUserInfo(Long id) {
// 获取B平台用户信息的逻辑
System.out.println("获取B平台用户信息的逻辑,用户ID:" + id);
UserInfo userInfo = new UserInfo();
return userInfo;
}
@Override
public PlatformChannelEnum getPlatformEnum() {
// 平台标识 -- B
return PlatformChannelEnum.B;
}
}
工厂类
@Component
public class PlatformServiceFactory {
private final Map<String, PlatformService> platformServiceMap = new HashMap<>();
@Autowired
public PlatformServiceFactory(List<PlatformService> services) {
services.forEach(service -> {
String platformType = service.getPlatformEnum().getPlatform();
platformServiceMap.put(platformType, service);
});
}
public PlatformService getService(String platform) {
PlatformService service = platformServiceMap.get(platform);
if (service == null) {
throw new ReturnException(ReturnEnum.UNKNOWN_PLATFORM_ERROR);
}
return service;
}
}
Service 层实现
@Service
public class UserPlatformServiceImpl implements UserPlatformService {
@Autowired
private PlatformServiceFactory serviceFactory;
@Override
public void userUnbind(String uid, UserUnbindReq request) {
String platform = request.getPlatform();
Long id = request.getId();
// 获取策略对象
PlatformService service = serviceFactory.getService(platform);
// 获取用户信息
UserInfo userInfo = service.getUserInfo(id);
// 执行解绑操作
service.unBind(userInfo);
}
}
优点
- 降低耦合度:通过工厂获取策略对象,无需知道具体策略类的实现。
缺点
- 工厂类逻辑复杂:工厂类需要维护策略映射,当策略种类较多时,逻辑可能会变得复杂。
3. 策略 + 工厂模式
定义策略接口
public interface PlatformStrategy {
void unBind(UserInfo userInfo);
UserInfo getUserInfo(Long id);
PlatformChannelEnum getPlatformEnum();
}
A平台具体策略
@Service
public class PlatformAStrategyImpl implements PlatformStrategy {
@Resource
private PlatformAMapper aMapper;
@Override
public void unBind(UserInfo userInfo) {
// A平台的解绑逻辑
System.out.println("解绑A平台用户,用户ID:" + userInfo.getId());
}
@Override
public UserInfo getUserInfo(Long id) {
// 获取A平台用户信息的逻辑
System.out.println("获取A平台用户信息的逻辑,用户ID:" + id);
UserInfo userInfo = new UserInfo();
return userInfo;
}
@Override
public PlatformChannelEnum getPlatformEnum() {
// 平台标识 -- A
return PlatformChannelEnum.A;
}
}
B平台具体策略
@Service
public class PlatformBStrategyImpl implements PlatformStrategy {
@Resource
private PlatformBMapper bMapper;
@Override
public void unBind(UserInfo userInfo) {
// B平台的解绑逻辑
System.out.println("解绑B平台用户,用户ID:" + userInfo.getId());
}
@Override
public UserInfo getUserInfo(Long id) {
// 获取B平台用户信息的逻辑
System.out.println("获取B平台用户信息的逻辑,用户ID:" + id);
UserInfo userInfo = new UserInfo();
return userInfo;
}
@Override
public PlatformChannelEnum getPlatformEnum() {
// 平台标识 -- B
return PlatformChannelEnum.B;
}
}
定义策略工厂
@Component
public class PlatformStrategyFactory {
private static final Map<String, PlatformStrategy> PLATFORM_STRATEGY_MAP = new HashMap<>();
@Autowired
public PlatformStrategyFactory(List<PlatformStrategy> strategies) {
strategies.forEach(strategy -> {
String platformType = strategy.getPlatformEnum().getPlatform();
PLATFORM_STRATEGY_MAP.put(platformType, strategy);
});
}
public PlatformStrategy chooseStrategy(String type) {
if (!PLATFORM_STRATEGY_MAP.containsKey(type)) {
throw new ReturnException(ReturnEnum.UNKNOWN_PLATFORM_ERROR);
}
return PLATFORM_STRATEGY_MAP.get(type);
}
}
Service 层实现
@Service
public class UserPlatformServiceImpl implements UserPlatformService {
@Autowired
private PlatformStrategyFactory strategyFactory;
@Override
public void userUnbind(String uid, UserUnbindReq request) {
String platform = request.getPlatform();
Long id = request.getId();
// 获取策略对象
PlatformStrategy platformStrategy = strategyFactory.chooseStrategy(platform);
// 获取用户信息
UserInfo userInfo = platformStrategy.getUserInfo(id);
// 执行解绑操作
platformStrategy.unBind(userInfo);
}
}
优点
-
客户端与策略类解耦:客户端通过工厂类获取策略对象,无需直接实例化具体策略类,降低耦合度。
-
策略类独立性:每个策略类独立实现接口,便于单独维护和扩展。
-
新增策略类方便:新增平台策略时,只需实现接口并注册到工厂类,符合开闭原则。
-
动态选择策略:客户端可根据平台类型动态选择策略对象,灵活性高。
-
工厂类集中管理:工厂类集中管理策略对象的创建逻辑,避免重复编写策略选择代码。
-
职责清晰:工厂类、策略类和 Service 层职责明确,便于维护。
-
集中管理:工厂类集中管理策略映射关系,便于调试和管理。
缺点
-
策略种类多时:工厂类中的映射表会变得庞大,逻辑可能复杂。
-
查找开销:工厂类每次获取策略对象时需在映射表中查找,可能带来性能开销。
-
初始化开销:工厂类在初始化时需加载所有策略类,可能增加启动时间。
总结
| 特性 | 策略+工厂结合 | 策略模式 | 工厂模式 |
|---|---|---|---|
| 解耦程度 | 高 | 高 | 中 |
| 扩展性 | 易于扩展 | 易于扩展 | 扩展性一般 |
| 灵活性 | 高 | 高 | 中 |
| 复杂度 | 中等 | 低 | 中 |
| 推荐场景 | 复杂系统,需灵活扩展 | 简单场景,需灵活切换 | 对象创建复杂,需统一管理 |
其实在项目上线后总结下来,还是策略+工厂是比较符合实际需求,也曾考虑过每个策略实现不同类型的出入参,实际看下来维护会比较困难,后续如果再额外增加C,D,E等平台只需要实现策略即可。不过项目初期时候很多需求没明确没办法定下模式,导致开始还都是if-else,switch等形式,随着项目进行逐步进行整个模式改造。