文章目录
代码优化之非核心代码的抽取问题
背景
为什么需要代码抽取非核心代码
随着版本的迭代和不同开发人员对接口的修改,通常以不改动老代码为原则进行微调,随着微调的积累,就逐渐产生非核心代码没有得到归纳梳理的情况。
非核心代码对原业务代码的影响
1,如果controller层出现非常大篇幅的逻辑判断,导致controller类代码行数非常大,定位问题的时候需要从接口一直往下寻找对应的service调用
2,如果是service出现大篇幅的逻辑判断,很容易跟原来的业务逻辑混淆,在定位的问题的时候,需要仔细阅读,另外在新增需求的时候,比较担心在大篇幅的逻辑里是否存在也对相对应的功能进行修改了,需要阅读检查,或者就干脆不混在原来代码中间增加逻辑,直接在后面继续逻辑处理,也就可能出现了再次多于的查表和修改表的问题发生。
处理方案:
私有方法抽取
这个大家都熟悉,pass
MiddleHandle处理类
算是私有方法的独立处理,中间的处理类并不是必须的,如果非核心的业务逻辑代码不是很多,其实可以不用独立处理,并且中间处理类其实还需要考虑到返回值的判断,中间类无法实现直接对中间类进行return返回响应等问题。如果controller非常大或者service非常大,中间处理类就很有必要。
例子:入参数据的检查抽取
这个controller存在100行的数据检查,抽取后美观了很多,而且比较容易虚招到核心的service调用。
类内聚
我觉得这个是一时使用一时爽,一直使用一直爽的方法,这个方法大家都懂,只是使用习惯问题。
类内聚可以结合数据封装和业务分离的概念来理解,最重要的功能是做数据封装,也可以做非核心业务抽取。
注意问题:
类内聚的方法名尽量避开get和set开头,如果需要使用get和set,则后面的英文不要与字段名相同。
尽量不采用原实体类(非必要情况),尽量才作用dto类进行数据拷贝后,再进行类内聚
例子:入参的数据准确性校验(非核心业务逻辑抽取)
数据封装和业务分离
我觉得这个是容易被忽视的一个问题,这里不关心封装的手段是封装到service的私有方法还是类内聚或者独立的middleHandle处理类,只涉及抽取的原则。
经常能遇到两个场景,一个是自己的代码在测试期间发现有点不美观了,另外一个是在别人的代码里增加自己的需求,而且这个需求影响面比较大,修改错地方可能造成无法预计的后果。这里说第二个场景。
如果可以在原来的代码上直接新增代码,建议先完成功能开发。如果是代码太多了梳理之后还是无从下手,就直接开整。(涉及到修改别人的代码,搬动前先沟通)
先对代码进行归类,重新标注注释(标记的注释有利于拆分和抽取代码用),然后对于同类功能属性的代码进行位置上的迁移调整,最后对每个模块进行分离。
第一步,加注释
第二步,确定是否存在数据库的查询,存在数据库查找,要么是按照查找前查找后区分,要么新增私有方法进行一次抽取,下面是存在数据检查,封装数据,查库,就需要考虑是否有必要改动代码。
第三步,考虑原来的封装方法是否进行重组。一般情况下可以不用重组。
第四步,考虑使用私有方法,数据处理类,类内聚等方式进行拆分。
(经常遇到代码中存在注释掉的代码,如果看年代是去年的,不删掉就留着下一位阅读)
(对于if else封装很长代码的,能去掉就去掉,不能去掉也要拆,实在不能拆,给个换行,idea才能收起代码块)
(代码重构后变动可能比较大,建议修改前备份,或者预留原来的接口,注释好修改时间和过期时间)
例子:通过StandarProductBaseInfoServiceMiddleHandle类和私有方法抽取将数据检查,数据封装和数据修改操作分开
复杂逻辑采用中间变量,减少数据库的操作次数
当存在某个业务逻辑需要再次操作数据库的时候,可以考虑采用中间变量,将数据操作合并到数据操作模块中
提取代码里的对象进行共享。
大逻辑代码拆解思路:
可分三大方向
1.数据检验(检查和数据验证),此处也可以分几个小方向拆解(数据检查一部分,数据验证一部分)
2.数据封装(包含部分关键数据验证,重要数据的封装),此处可根据实际业务可拆分多个处理方法,尽量业务独立开,让业务与代码相紧合,不相干业务可进行松耦合模式处理,让后期开发人员再开发某一快业务时,只关心其相关业务代码块,
可重用而且复用比较高的可整成相关模板方法或者工具类,还有思路不要把所有业务逻辑代码都往一个service逻辑层去装,做到相应业务逻辑交给相应service处理层
3.数据保存和异步日志(可把数据同步和异步的进行拆分,保证一个事务之间数据的一致性,如跟异步数据有紧密相关的,尽量做到数据一致性,把异步放在最后一步操作与手动回滚机制)
复杂的if else结构,转用私有方法return来处理
下面例子如果是直接书写到与match对象同级,将会导致不断判断非空,然后执行下一步,最终会导致非常多的if else结构嵌套
if(CollectionUtils.isNotEmpty(list)) {
//其他的if else结构
} else {
}
所以采用私有方法就能对else进行提前返回。
if (CollectionUtils.isEmpty(textureSKUList)) {
match.canNotMatch();
return ;
}
if (Objects.nonNull(in.getWageCraftId())) {
textureSKUList = textureSKUList.stream().filter(x->x.getWageCraftId().equals(in.getWageCraftId())).collect(Collectors.toList());
} else {
match.setWageCraftMatching(MatchingResults.MATCH_NULL);
}
if (CollectionUtils.isEmpty(textureSKUList)) {
match.setWageCraftMatching(MatchingResults.MATCH_NO);
return ;
}
match.setWageCraftMatching(MatchingResults.MATCH_YES);