策略 + 工厂实战
业务场景
开发过程中可能会遇到分支的业务,比如根据不同的 状态做不同的操作,会写很多if,伪代码如下:
void methodA(){
if (StatusEnums.ONE.getCode().equals(projectStatus)){
// do some thing
} else if (StatusEnums.TWO.getCode().equals(projectStatus)){
// do other thing
} else if (StatusEnums.THREE.getCode().equals(projectStatus)){
// do one more thing
} else {
// finally
}
}
这种代码的问题就在于很难管理,每个分支有【分支独特的逻辑】,代码长且不容易维护,可拓展性差。
工厂 + 策略可以解放当前方法中的多段 if 判断, 可以在不修改原代码的情况下拓展业务逻辑分支,非常优美。
工厂 + 策略
让工厂将所有的策略注入Spring的IOC容器,这样可以很方便的获取所有分支策略,
核心思想是使用【工厂类】将实现【逻辑抽象操作的接口】的【所有实现类类】注入到工厂的Map中,然后在【业务代码】中将工厂类作为Bean使用,从工厂中获取对应状态的处理类,调用抽象处理方法去做特殊的操作。
一共有三种角色:
ProjectConfirmHandler 代入到之前的伪代码中,就是【分支独特的逻辑】的抽象接口
CancelStatusHandler ConfirmStatusHandler NeedResponseStatusHandler RefuseStatusHandler 这四个实现这个接口的类就代表有独特的逻辑,根据伪代码中的
projectStatus状态做不同的操作。当然他们的projectStatus是不同的。
ProjectConfirmStatusFactory 是状态工厂,负责将所有的实现类进行收集,注入IOC容器
代码实现
工厂类ProjectConfirmStatusFactory
/**
* @description 状态注入工厂
* @create 2022-02-08 20:20
*/
@Service
@AllArgsConstructor
public class ProjectConfirmStatusFactory {
/**
* 策略工厂map
*/
private Map<Integer, ProjectConfirmHandler> factoryMap;
/**
* 注入 所有处理类
*/
private final List<ProjectConfirmHandler> projectConfirmHandlers;
/**
* 通过 @PostConstruct 注解,在 ProjectConfirmHandler 实例化后,用所有实现类来初始化 factoryMap
*
* @date 2022/2/8 20:34:18
*/
@PostConstruct
public void init() {
// 没有处理类就返回
if (CollUtil.isEmpty(projectConfirmHandlers)) {
return;
}
// init map
factoryMap = new HashMap<>(projectConfirmHandlers.size());
// 将注入的 service list 转化成 map
projectConfirmHandlers.forEach(item -> {
// 取出处理类对应的 项目确认状态
final Integer projectConfirmStatus = item.getProjectConfirmStatus();
// 项目确认状态 重复性校验,一个状态只能存在一个处理类
AssertUtils.isFalse(factoryMap.containsKey(projectConfirmStatus), "一个 projectConfirm 只能有一个策略处理类");
// put
factoryMap.put(projectConfirmStatus, item);
});
}
/**
* 获取对应项目确认状态的 处理类
*
* @param projectConfirmStatus
* @return 对应项目状态的处理类
* @date 2022/2/8 20:41:32
*/
public ProjectConfirmHandler getHandler(Integer projectConfirmStatus) {
return Optional.ofNullable(factoryMap.get(projectConfirmStatus)).orElseThrow(() -> new BusinessException("找不到对应的项目确认状态处理类"));
}
}
抽象操作接口ProjectConfirmHandler
/**
* @description 项目确认策略处理类
* @create 2022-02-08 20:13
*/
public interface ProjectConfirmHandler {
/**
* 根据项目确认时的确认状态处理控制前端按钮显示
*
* @param projectConfirmBO
* @param quotationEntity
* @param projectInfoVO
* @date 2022/2/8 20:18:37
*/
void handle(ProjectConfirmBO projectConfirmBO, ProjectSupplierQuotationEntity quotationEntity, ProjectInfoVO projectInfoVO);
/**
* 获取 这个策略处理类的类型用于区分,这里是 projectConfirmStatus 项目确认状态
*
* @return 项目确认状态
* @date 2022/2/8 20:19:25
*/
Integer getProjectConfirmStatus();
}
具体操作类 取消状态处理类CancelStatusHandler
/**
* @description 采购单位【取消】状态策略处理类
* @create 2022-02-08 20:13
*/
@Service
public class CancelStatusHandler implements ProjectConfirmHandler {
/**
* 【采购单位【取消】状态策略处理类】控制前端按钮显示
*
* @param projectConfirmBO
* @param quotationEntity
* @param projectInfoVO
* @date 2022/2/8 20:18:37
*/
@Override
public void handle(ProjectConfirmBO projectConfirmBO, ProjectSupplierQuotationEntity quotationEntity, ProjectInfoVO projectInfoVO) {
// do one thing
}
/**
* 拒绝
*
* @return 项目确认状态
* @date 2022/2/8 20:19:25
*/
@Override
public Integer getProjectConfirmStatus() {
return ProjectConfirmStateEnums.CANCELED.getCode();
}
}
具体操作类 确认状态处理类ConfirmStatusHandler
/**
* @description 供应商【确认】策略处理类
* @create 2022-02-08 20:13
*/
@Service
public class ConfirmStatusHandler implements ProjectConfirmHandler {
/**
* 【供应商确认状态】控制前端按钮显示
*
* @param projectConfirmBO
* @param quotationEntity
* @param projectInfoVO
* @date 2022/2/8 20:18:37
*/
@Override
public void handle(ProjectConfirmBO projectConfirmBO, ProjectSupplierQuotationEntity quotationEntity, ProjectInfoVO projectInfoVO) {
// do other thing
}
/**
* 项目确认
*
* @return 项目确认状态
* @date 2022/2/8 20:19:25
*/
@Override
public Integer getProjectConfirmStatus() {
return ProjectConfirmStateEnums.CONFIRMED.getCode();
}
}
其他两个状态的策略处理类就不多赘述了,他们的区别是与 getProjectConfirmStatus 方法返回的状态不同,返回的就是工厂用于区分不同处理逻辑的标识。
使用
/**
* 注入 项目确认状态工厂
*/
@Resource
private ProjectConfirmStatusFactory projectConfirmStatusFactory;
/**
* 实际操作方法
*/
void methodA(){
// 确认状态
Integer projectConfirmStatus = projectConfirmBO.getState();
// 获取工厂中的处理当前项目确认状态的策略处理类,就是从Map中获取对应状态的处理类
ProjectConfirmHandler handler = projectConfirmStatusFactory.getHandler(projectConfirmStatus);
// 执行实际操作
handler.handle(projectConfirmBO, quotationEntity, projectInfoVO);
}