用策略模式重构工作中的代码

策略模式:

所谓策略模式,其思想是针对一组算法,将每一种算法都封装到具有共同接口的独立的类中,从而是它们可以相互替换。策略模式的最大特点是使得算法可以在不影响客户端的情况下发生变化,从而改变不同的功能。

实际项目中,重构前的代码:

if (processType != null) {
    if (processType.equals(BizTypeEnums.TRAVEL.getCode())) {
        travelApplyService.updateStatus(businessKey, FIALSTATUS);
    }
    if (processType.equals(BizTypeEnums.LOAN.getCode())) {
        borrowBillService.updateStatus(businessKey, FIALSTATUS);
    }
    if (processType.equals(BizTypeEnums.EXPENSE.getCode())) {
        expenseInfoService.updateStatus(businessKey, FIALSTATUS);
    }
    if (processType.equals(BizTypeEnums.REFUND.getCode())) {
        refundInfoService.updateStatus(businessKey, FIALSTATUS);
    }
    if (processType.equals(BizTypeEnums.PAYMENT.getCode())) {
        expenseInfoService.updateStatus(businessKey, FIALSTATUS);
    }
}

这段代码逻辑是,从消息队列中获取到的消息体中会有一个业务类型的标识processType,现根据processType来决定要走那个service类的方法。

要说这段代码的好处就是写的时候简单,一幕了然。但是一旦了解了后续会添加新的service类并且也有类似的updateStatus方法之后,而且现在除了updateStatus方法之外还有好多个地方有类似这样的a、b、c方法,就会隐隐觉得蛋疼。这种看似冗余重复的代码能不能变得看起来更“简洁”呢?

 

记录下我是怎么用策略模式来优化类似这种代码的吧。

1、定义一个公用类(策略类):BaseService

public interface BaseService {
    /**
     * 更改状态
     * @param number
     * @param status
     * @return
     */
    Boolean updateStatus(String number, Integer status) throws GolfServiceException;

    /**
     * 获取流程定义id
     * @param processType 可为null
     * @return
     */
    String getProcessId(String processType);


    /**
     * 获取详情数据
     * @param businessKey
     * @return
     */
    Map getData(String businessKey);

    /**
     * 根据申请人id和状态查找单据
     * @param processQueryRequest
     * @return
     */
    PageResult queryByApplyUserIdAndStatus(ProcessQueryRequest processQueryRequest);

    /**
     * 返回实现类方法的流程类型
     * @return
     */
    String getType();
}

注意这个getType方法,后面在工厂类中,要根据这个来觉定使用那个具体的service。

2、每个具体的service都继承策略类BaseService

public interface BorrowBillService extends BaseService{
。。。。。
}
public class BorrowBillServiceImpl implements BorrowBillService {
...

    /**
     * 重点是这个getType方法要返回本service类的所属类型
     */
    @Override
    public String getType() {
        return BizTypeEnums.LOAN.getCode();
    }

    /**
    * 对策略的实现
    */
    @Override
    public Boolean updateStatus(String number, Integer status) {
    //    具体的策略实现.....
    }
...
}

3、工厂类

@Service("processServiceFactory")
@Slf4j
public class ProcessServiceFactory implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    /**
     * 策略实现类集合
     */
    private Map baseServiceMap = new HashMap<>(16);

    /**
     * 根据流程类型产生相应的策略
     *
     */
    public BaseService createBaseService(String processType) throws RuntimeException {
        if (processType != null) {
            return baseServiceMap.get(processType);
        } else {
            throw new RuntimeException("processType error.");
        }
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    
    /*
     * 在服务器加载servlet的时候把spring容器中的实例化的bean都放到map中,map中的key就为
     * 上面提到的type
     */
    @PostConstruct
    public void initProcess() {
        Map baseServiceBeansMap = applicationContext.getBeansOfType(BaseService.class);
        if (MapUtils.isNotEmpty(baseServiceBeansMap)) {
            for (Map.Entry ent : baseServiceBeansMap.entrySet()) {
                BaseService baseServiceWrapper = ent.getValue();
                String types = baseServiceWrapper.getType();
                if (types.contains(",")) {
                    String[] typeArray = types.split(",");
                    for (String type : typeArray) {
                        baseServiceMap.put(type, baseServiceWrapper);
                    }
                } else {
                    baseServiceMap.put(types, baseServiceWrapper);
                }
            }
        } else {
            throw new RuntimeException("No BaseService wrapper beans.");
        }
    }

4、在处理消息时,代码就简化为了

    //注入工厂类
    @Autowired
    ProcessServiceFactory processServiceFactory;

    @Override
    public Map getData(HumanTask humanTask) {
        // 省略....

        //此处仅需告诉工厂类,我现在是什么类型的消息,工厂类就会给一个对应的service来给你处理
        //这次的任务
                BaseService baseService = processServiceFactory.createBaseService(processType);
                data = baseService.getData(businessKey);

        //省略....
    }

通过这个重构,也明细的看出了策略模式的优缺点:

优点:可以动态的改变对象的行为

缺点:1、代码逻辑变得更为复杂。2、客户端必须知道所有的策略类,并决定使用哪一个策略类。

 

你可能感兴趣的:(JAVA,设计模式)