策略 + 工厂实战

200 阅读4分钟

策略 + 工厂实战

业务场景

开发过程中可能会遇到分支的业务,比如根据不同的 状态做不同的操作,会写很多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使用,从工厂中获取对应状态的处理类,调用抽象处理方法去做特殊的操作。

一共有三种角色:

image-20220216173413489.png

ProjectConfirmHandler 代入到之前的伪代码中,就是【分支独特的逻辑】的抽象接口

CancelStatusHandler ConfirmStatusHandler NeedResponseStatusHandler RefuseStatusHandler 这四个实现这个接口的类就代表有独特的逻辑,根据伪代码中的projectStatus状态做不同的操作。当然他们的projectStatus是不同的。

ProjectConfirmStatusFactory 是状态工厂,负责将所有的实现类进行收集,注入IOC容器

image-20220216174903797.png

代码实现

工厂类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);
}