文档章节

一段业务代码的重构过程

drv
 drv
发布于 2017/06/27 15:36
字数 1350
阅读 12
收藏 0

    最近review代码,然后带着程序员重构了一段,发现语法方面居然花了不少时间,然后感觉这种情况还是挺典型的,于是记录一下,下次就不用从语法教起了。

    首先是review的时候看到了这样一段代码(命名都被我改掉了,也只改了命名):

        String list = "";
        if ("1".equals(inputPara.getA())) {
            if (0 == Optional.ofNullable(bo).map(account -> account.getA()).orElse(0)) {
                list = "A,";
            }
        }
        if ("1".equals(inputPara.getAb())) {
            if (0 == Optional.ofNullable(bo).map(account -> account.getAb()).orElse(0)) {
                list = list + "AB,";
            }
        }
        if ("1".equals(inputPara.getAbc())) {
            if (0 == Optional.ofNullable(bo).map(account -> account.getAbc()).orElse(0)) {
                list = list + "ABC,";
            }
        }
        if ("1".equals(inputPara.getAbca())) {
            if (0 == Optional.ofNullable(bo).map(account -> account.getAbca()).orElse(0)) {
                list = list + "ABCA,";
            }
        }
        if ("1".equals(inputPara.getAbcab())) {
            if (0 == Optional.ofNullable(bo).map(account -> account.getAbcab()).orElse(0)) {
                list = list + "ABCAB,";
            }
        }
        list = list.trim().substring(0, list.lastIndexOf(","));

    看到这段代码的时候,就很不舒服,几个判断里面的逻辑是一模一样的,没想到还发现下面两段代码,整个人瞬间就不好了。。。

        String list = "";
        if ("0".equals(inputPara.getA())) {
            if (1 == Optional.ofNullable(bo).map(b -> b.getA()).orElse(0)) {
                list = "A,";
                bo.setA(0);
            }
        }
        if ("0".equals(inputPara.getAb())) {
            if (1 == Optional.ofNullable(bo).map(b -> b.getAb()).orElse(0)) {
                list = list + "AB,";
                bo.setAb(0);
            }
        }
        if ("0".equals(inputPara.getAbc())) {
            if (1 == Optional.ofNullable(bo).map(b -> b.getAbc()).orElse(0)) {
                list = list + "ABC,";
                bo.setAbc(0);
            }
        }
        if ("0".equals(inputPara.getAbca())) {
            if (1 == Optional.ofNullable(bo).map(b -> b.getAbca()).orElse(0)) {
                list = list + "ABCA,";
                bo.setAbca(0);
            }
        }
        if ("0".equals(inputPara.getAbcab())) {
            if (1 == Optional.ofNullable(bo).map(b -> b.getAbcab()).orElse(0)) {
                list = list + "ABCAB,";
                bo.setAbcab(0);
            }
        }
        list = list.trim().substring(0, list.lastIndexOf(","));
        String[] slist = callback.split(",");
        for (String str : slist) {
            if ("A".equals(str)) {
                bo.setA(1);
            } else if ("AB".equals(str)) {
                bo.setAb(1);
            } else if ("ABC".equals(str)) {
                bo.setAbc(1);
            } else if ("ABCA".equals(str)) {
                bo.setAbca(1);
            } else if ("ABCAB".equals(str)) {
                bo.setAbcab(1);
            } else {
                continue;
            }
        }

    前两段代码看上去格式完全没有变化,判断逻辑排除掉“0”和“1”就没啥区别;然后就是常量字符串写了三次,其实用的是一个玩意;还有个小问题Optional用的多余明明只比结果就好,还要转成0再比。第三段代码还有个问题,就是循环内部的判断,判断“A”的时候只需要一次,但是判断“ABCAB”的时候需要5次,同时还有人为耦合5次判断的嫌疑。

    先来前两段代码,首先业务逻辑第一段是遇到“0”判断状态是否是“0”,不是就把状态改为1,同时记录与状态相关属性对应的字符串,第二段是遇到“1”改“0”其它与第一段一样。第一件事,先不管逻辑,先把常量字符串弄出来,好多地方用不能一个地方写一个。

enum BizEnum {
    a("A"),
    ab("AB"),
    abc("ABC"),
    abca("ABCA"),
    abcab("ABCAB");
    
    private String value;
    
    BizEnum(String value){
        this.value = value;
    }
    
    public String getValue() {
        return value;
    }
}

    然后就是内部的逻辑了,前两段代码的外层是判断参数是否符合逻辑的,先不管,先看每个判断的内部,符合了判断逻辑后的处理方式是完全相同的,先合一下,这里不一样的很明显只有字段反射就好了,而字段是与常量一一对应的:

            if(Integer.valueOf(0).equals(BeanUtil.get(b, attribute))){
                String grant = BizEnum.valueOf(attribute).getValue();
                return grant;
            }
            return "";
            if(Integer.valueOf(1).equals(BeanUtil.get(b, attribute))){
                BeanUtil.set(b, attribute, 0);
                String grant = BizEnum.valueOf(attribute).getValue();
                return grant;
            }
            return "";

    这里“1”、“0”其实按说可以接参数,再不济也应该是常量,不过一是实际逻辑就是这样的,把业务逻辑固化下来也没啥坏处,而且也没有别的需要传参的理由,至于常量...,反正代码不是我改的(甩锅),只要能过得去也就算了,也没必要管那么细。

    判断里面处理完了,回头看外面的判断,其实都是一样一样的,合成一个就完了:

    private String changeValueLogic(InputPara inputPara, BO bo, String change, ChangeBO changeBO){
        StringBuilder stringBuilder = new StringBuilder();
        for (BizEnum aEnum : BizEnum.values()){
            String string = (String) BeanUtil.get(inputPara, aEnum.name());
            if(change.equals(string)){
                String grant = changeBO.updateBO(bo, aEnum.name());
                if(StringUtils.isNotEmpty(grant)){
                    stringBuilder.append(grant);
                    stringBuilder.append(",");
                }
            }
        }
        if(stringBuilder.length() == 0){
            return "";
        }
        String result = stringBuilder.deleteCharAt(stringBuilder.lastIndexOf(",")).toString();
        return result;
    }

    参数有点多,不过还是过得去就算了,判断逻辑就是根据业务对象状态和对应枚举,取出结果判断,符合就改掉状态,并且记录下常量,这里会看到有一个ChangeBo,这是一个接口:

interface ChangeBO{
    String updateBO(BO bo, String attribute);
}

    用这个接口的原因是毕竟只有外面判断一样,内部的逻辑还是有区别的,所以就要将内部判断的逻辑传进来,看一下开头那两段代码的优化结果就知道了:

    public void createBiz(InputPara inputPara, BO bo) {
        ChangeBO changeBO = (b, attribute) -> {
            if(Integer.valueOf(0).equals(BeanUtil.get(b, attribute))){
                String grant = BizEnum.valueOf(attribute).getValue();
                return grant;
            }
            return "";
        };
        String result = this.changeValueLogic(inputPara, bo, "1", changeBO);
        System.out.println(result);
    }
    public void updateBiz(InputPara inputPara, BO bo) {
        ChangeBO changeBO = (b, attribute) -> {
            if(Integer.valueOf(1).equals(BeanUtil.get(b, attribute))){
                BeanUtil.set(b, attribute, 0);
                String grant = BizEnum.valueOf(attribute).getValue();
                return grant;
            }
            return "";
        };
        String result = this.changeValueLogic(inputPara, bo, "0", changeBO);
        System.out.println(result);
    }

    这样这两个方法内部的逻辑就内聚了,一个方法就只干一件事了,而且再有并列的状态增加进这个BO,只需要增加对应的枚举项,这里的代码都不需要动了。

    接下来就是第三段代码,其实第三段代码非常契合状态模式,直接照着套就好了,我也不多说了:

    private void update(String callback, BO bo) {
        Map<String, Consumer<BO>> map = this.getBs();
        String[] sList = callback.split(",");
        for (String str : sList){
            Consumer<BO> hkcgAccountConsumer =  map.get(str);
            if(null == hkcgAccountConsumer){
                continue;
            }
            hkcgAccountConsumer.accept(bo);
        }
    }
    
    private Map getBs(){
        Map<String, Consumer<BO>> map = new HashMap<>();
        map.put(BizEnum.a.getValue(), (b) -> b.setA(1));
        map.put(BizEnum.ab.getValue(), (b) -> b.setAb(1));
        map.put(BizEnum.abc.getValue(), (b) -> b.setAbc(1));
        map.put(BizEnum.abca.getValue(), (b) -> b.setAbca(1));
        map.put(BizEnum.abcab.getValue(), (b) -> b.setAbcab(1));
        
        return map;
    }

==========================================================

咱最近用的github:https://github.com/saaavsaaa

微信公众号:

           

© 著作权归作者所有

drv

drv

粉丝 2
博文 57
码字总数 75382
作品 0
东城
架构师
私信 提问
如何来一次说干就干的重构 (流程篇)

摘要: 科学的重构流程。 原文:如何来一次说干就干的重构 (流程篇) 作者:逐鹿 IT, 猛猛如玉 Fundebug经授权转载,版权归原作者所有。 前言 随着公司业务的爆炸式的增长,需求规模和用户规模...

Fundebug
04/19
0
0
架构之重构的12条军规

注】架构之重构的12条军规(上)发布以后,一些读者着急要下篇,所以在这里我把上下篇合并成一篇,让大家可以阅读完整版,不用分开看了。 对于开发者来说,架构设计是软件研发过程中最重要的...

罗文浩
2015/12/01
149
0
重构第一步:分解大函数

分解大函数 分解大函数.png 为什么会产生大函数 随着业务逻辑的一次次变更和越来越复杂,不停地往函数里面添加代码,再加上一些不合理地设计,原本清晰而简单的程序变得越来越复杂,天长日久...

JasonWangUp
2018/01/20
0
0
Drizzle 2011.07.21,精简的MySQL分支

该版本继续对代码进行重构,同时继续完善存储过程接口,提升了存储引擎 API 测试,修复了很多bug。 Drizzle,一个精简版的MySQL分支,在目前的MySQL代码基本之上,将存储过程、视图、触发器、...

红薯
2011/07/07
408
1
从把3000行代码重构成15行代码谈起

如果你认为这是一个标题党,那么我真诚的恳请你耐心的把文章的第一部分读完,然后再下结论。如果你认为能够戳中您的G点,那么请随手点个赞。 把三千行代码重构为15行 那年我刚毕业,进了现在...

拉偶有所依
2015/01/12
345
1

没有更多内容

加载失败,请刷新页面

加载更多

Taro 兼容 h5 踩坑指南

最近一周在改造 公羊阅读🐏 Taro 版本适配 h5 端,过程中改改补补,好不酸爽。 本文记录📝遇到的问题,希望为有相同需求的哥们👬节约点时间。 Taro 版本:1.3.9。 client_mobile_taro...

dkvirus
今天
4
0
Spring boot 静态资源访问

0. 两个配置 spring.mvc.static-path-patternspring.resources.static-locations 1. application中需要先行的两个配置项 1.1 spring.mvc.static-path-pattern 这个配置项是告诉springboo......

moon888
今天
3
0
hash slot(虚拟桶)

在分布式集群中,如何保证相同请求落到相同的机器上,并且后面的集群机器可以尽可能的均分请求,并且当扩容或down机的情况下能对原有集群影响最小。 round robin算法:是把数据mod后直接映射...

李朝强
今天
4
0
Kafka 原理和实战

本文首发于 vivo互联网技术 微信公众号 https://mp.weixin.qq.com/s/bV8AhqAjQp4a_iXRfobkCQ 作者简介:郑志彬,毕业于华南理工大学计算机科学与技术(双语班)。先后从事过电子商务、开放平...

vivo互联网技术
今天
19
0
java数据类型

基本类型: 整型:Byte,short,int,long 浮点型:float,double 字符型:char 布尔型:boolean 引用类型: 类类型: 接口类型: 数组类型: Byte 1字节 八位 -128 -------- 127 short 2字节...

audience_1
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部