关于我用设计模式对公司代码重构的这件事

(所有代码皆是脱敏后的伪代码)

1. 基本需求:

这是一个单独的服务,主要负责顺序执行十几个计算类的任务Task。需要统计每天Task的执行情况,卡在哪里,做一些手动重试和手动流程回滚等操作。

每个Task正常是按时间约定每天定时按顺序执行,前一个Task失败会导致后续的Task都不能执行。Task执行异常会有相关出错误原因,时间等相关日志留存。

其中有两个状态,当日的总的流程状态我们用 totalStatus表示, 每一个任务自己的状态我们用 taskStatus来表示。

 

 

2.原始实现

看一下之前的设计

非常的简单,一个任务就是一个Task类,每个类中有一个定时任务的开关schedule(),

schedule()方法仅是作为定时任务的入口,调用的是audit()方法来做具体的计算,包括调用其它服务查数据,做大量的计算,和生成或拉取文件,最后入库的操作。

而reAudit()方法是作为手动调用的入口,把上边那些计算操作都走一遍,是的 也在代码里重复写了一遍。。。仅是有入参判断等等略微差异。

并且audit()和reAudit()方法中都有一个大大的try catch包裹住,用来捕捉异常情况然后做变更任务的状态,日志留痕等操作。

每个Task类的伪代码大概就是这样,reAudit()几乎和audit()是一模一样的,这里就不贴了

 

3. 暴露的问题

1 每个任务都会写类似重复的逻辑代码,主要那四步骤

2 每个任务都有try catch这种处理,处理错误状态以及错误信息

3 扩展性不好,如果新添加一个任务,所有的这些逻辑都要重复写一遍

4 手动执行相关接口,非常容易响应超时

5 流程回滚是在代码里一个一个调用的(如下图)

 

 

4.思考与重构

1.每个类中都有的相似代码甚至重复代码,找到他们的共同点抽象出来

很容易让人想到模板模式,把程序化的流程执行这些东西抽象到父类,子类只需要实现具体细节。

将每个Task中共有的步骤1,2,3,4提到抽象层,具体实现由各个Task继承并实现

audit()与reAudit()方法也提到抽象层,其他的暂时都没动。

 

2.此时每个Task类的代码已经很清爽了,仅有一个定时任务方法和四个步骤的具体实现

但是抽象父类audit()方法优点冗长,我觉得他做了很多不该做的事

Task的职责应该仅仅为了任务的执行逻辑而服务,不应该带状态处理,日志打印这些操作。

对于这种方法执行前后需要做一些操作的逻辑,很容易让人在设计模式中找到我们的 代理模式

我这里使用的是静态代理,完全可以满足需求

把audit()抽象到接口,使代理类TaskProxy和AbstractTask都继承该接口

很标准的静态代理,代码易懂,我就不墨迹了

 

3. 到此代码就已经很清爽了,如果新增加一个任务只需要继承AbstractTask,实现do1(),do2(),do3(),do4()就可以了,其他的统统省掉

还有一个问题,

当清算整体回滚操作时,是在代码里写死的执行顺序 (可以翻一下上边的rollback()方法)

这种按照顺序一个接一个的执行有没有容易想到类似于 责任链模式

我们可不可以把每个Task串在一起串成一个链,回滚的话就按链的顺序执行就好了。

(根据责任链模式,应该前一个Task中存下一个Task,上一个执行完直接交给下一个。我觉得这样实现不太好,如果哪天产品经理一拍脑门Task的顺序变了或者其中增减了Task,改起来挺难受的)

(莫不如直接记录每个Task在顺序序号,直接按序号执行就完事了,要改也只需要改序号。)

 

由于每个Task都是基于SpringIOC注入的,我们直接依赖Spring容器这个大工厂,构建一个小工厂。

创建了一个枚举类,记录了每个Task的生辰八字,其中包括各个Task执行顺序编号和在Spring中的Bean名称

我们创建一个新的类TaskManager,用来管理这些Task。

在初始化的时候,在Spring容器中找到这些Task实例对象,根据按照顺序存成一个链表,

而rollbak()方法就直接for循环遍历链表,把Task交给代理类,执行audit()方法就可以了。

 

各司其职,

TaskManager负责获取并管理Task对象,Task顺序链表。

TaskProxy负责Task的执行前后的增强,更新状态,异常捕获并日志留存。

各个Task仅是负责底层实现逻辑,实际的计算啊,入库等操作。

 

4.最后手动直接Task操作接口响应超时的问题

直接用线程池改成异步执行就好了。单例模式获取到线程池,实现异步执行,就不赘述了。

  

5. 总结

本次利用了几种设计模式的思想对已有代码进行了简单的重构,感觉收获还是挺多的。

至少让代码干净简洁了不少,更易读和可维护。  

     

可以明显的看到整个task包的大小缩了三分之二,其中每个Task类从二三百行 缩到了四五十行,实现了瘦身

 

还是希望大家平时在开发过程中可以多一些思考,即便做不到代码优雅,但求尽量简洁易读。

至于那种一打开上千行的类,一个方法几百行,公司给我配的2核cpu的虚拟机是真的顶不住。

 

技术平平,水平有限,如有任何漏洞还请指正

 

posted @ 2022-01-17 21:09  六小扛把子  阅读(228)  评论(1编辑  收藏  举报