记一次重构经历

背景:最近新接触一个web项目,要求新增加一个审批流程。简化抽象模型,订单分为三种A\B\C。其中AB的审批流程完全一致,简化为审批1->审批2->审批后动作。C的审批流程略有不同,简化为审批0->审批1->审批2->审批后动作。现在要做的一个功能是要在订单C上增加一个审批流程变为:审批0->审批3->审批1->审批2->审批后动作。

很简单的一个功能,却花费了我近两天的时间。时间主要花费在了读代码和重构代码上,下面说一下我的重构过程。

以前的代码就是一个大逻辑,先是if判断订单类型,再if判断订单状态,再执行对应审批流程。

if(订单类型==A){

     if(!passed){

          doUnPassed();

     }

     if(订单状态==审批1){

           do审批1();

      }else if(订单状态==审批2){

           do审批2();

           do审批完成();

      }else{

           throw Exception(); 

     }

}else if ()......

很大的一个判断逻辑,可以想象到,最开始可能就是一个订单,一种审批流程,所以简单一个处理方法就满足要求。后来加了一个审批流程,就增加了一个else逻辑。再增加一种订单类型,在后面增加一个if else逻辑。久而久之,就变成了一个超级庞大的逻辑。也没人再敢改,牵一发动全身,并且这代码经过若干人手流转,也很难有人可以全面了解整体的流程了。

这次让我加一个审批逻辑,我就已经感觉到很困难了,所以我决定彻底重构。

首先理清楚整个代码逻辑,就是我前面所说的背景。

然后开始进行重构,可以看到三种订单类型,审批流程基本一致。很容易想到,第一步先把公共的流程剥离出来,由父类实现,个性化的流程由子类重写。这里就是模板模式,基本的类图如下:

第一步重构完成,类的结构变得比较清晰,流程也比较明确了,每种订单的个性化需求也满足了。调用起来却不太方便,还需要根据订单类型创建不同对象,很容易想到用工厂模式。三类订单审批类实现同一个接口,由工厂创建对应实例,再一次重构后类图:

简单的重构就算完成了,整个代码清爽了很多。但是作为追求完美的我不能这么满足。我们可以看到,如果增加一个审批流程依旧很麻烦,比如订单A需要增加一个审批流程4,那么需要修改抽象父类的审批流程逻辑、增加一个抽象方法审批4,每个子类都要实现这个抽象方法。

怎么处理,可以更方便的增加审批流程,每种订单之间不会相互影响。我们可以把审批流程作为一个责任链,订单的每种状态对应一个负责处理的单元。所有订单对应一个完整的责任链,再配合上状态模式,由订单当前的状态决定责任链中哪个单元来处理。这样某种订单增加一个审批流程,只需要给他增加一个状态,再在责任链中增加一个处理单元即可。如下简化后的代码

public class Service1 extends BaseApprovalService implements IService{
   private Operator op;
   private String state;

   @Override
   public void approval() {
       super.doApproval(state);
   }

  
   @Override
   protected void after() throws ServiceException{
      //订单审批结束后执行
   }

   @Override
   protected void before() throws ServiceException {
      //订单审批前执行
   }

}

抽象父类也变的简单明了:

public abstract class BaseApprovalService {
   public void approvalOrder(String state) throws ServiceException {
      before();
      if(!passed){
         //不通过处理
      }else {
         getOp().next(state).handler();
      }
      after();
   }
   protected abstract void after() throws ServiceException;
   protected abstract void before() throws ServiceException;
}

至此,算是重构完成。增加新的订单流程变得简单方便,增加新的订单种类也很方便。而且留了个性化的接口before和after处理。

个人水平有限,只能重构到这样子了,看着新的代码还是感觉很开心。上学时候老师总说见字如见人,写的字能代表一个人。

现在作为程序猿,见代码如见人。

发布了45 篇原创文章 · 获赞 21 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/ly262173911/article/details/84482873