• 工作中的重构:提高代码质量(一)


    1) continue/break语句过多

    continue/break本身是循环的流程控制关键字,但不应该滥用,否则将导致代码可读性降低。一个循环体内尽量只出现一次continue/break语句。
    origin:

            for (Object commerceItem : commerceItems) {
                if (commerceItem == null) {
                    continue;
                }
                NGPCommerceItemImpl lNGPCommerceItemImpl = (NGPCommerceItemImpl) commerceItem;
                if (lNGPCommerceItemImpl.getCatalogRefId() == null) {
                    continue;
                }
                if (lNGPCommerceItemImpl.getCatalogRefId().equals(addItems[0].getCatalogRefId())) {
                    addedcommerceItem = lNGPCommerceItemImpl;
                }
            }

    ①此处两个continue语句相邻,两者间没有其他的代码(业务逻辑),可以将两个continue语句合并在一起。
    corrected1:

      for (Object commerceItem : commerceItems) {
               NGPCommerceItemImpl commerceItemImpl = (NGPCommerceItemImpl) commerceItem;
                if (commerceItemImpl== null || commerceItemImpl.getCatalogId() == null) {
                    continue;
                }
                if (commerceItemImpl.getCatalogRefId().equals(addItems[0].getCatalogRefId())) {
                    addedcommerceItem = commerceItemImpl;
                }
            }

    上面的代码还是有些问题的:②commerceItem 到底是不是NGPCommerceItemImpl类型还不一定(这是以前别人写的代码,都在生产环境运行了好几年了,当前它一定是NGPCommerceItemImpl类型),如果未来添加了新的类型NGPCommerceItemImpl2,那是时commerceItem 还恰巧就是NGPCommerceItemImpl2类型,此时就会出现类型转换异常,因此要事先做类型判断。③另外,注意循环体内的重要代码就赋值的一行代码“addedcommerceItem = commerceItemImpl”,continue/break本省是用来减少大段大段的if块代码,continue/break和goto语句类似,都改变了代码执行原有的方向,能不用就尽量不用它。可以用去反条件的if语句替代它。
    corrected2:

    for (Object commerceItem : commerceItems) {
         if (!(commerceItem instanceof NGPCommerceItemImpl)) {
             continue;
         }
         NGPCommerceItemImpl commerceItemImpl = (NGPCommerceItemImpl) commerceItem;
         if (commerceItemImpl != null || commerceItemImpl.getCatalogId() != null
             && commerceItemImpl.getCatalogRefId().equals(addItems[0].getCatalogRefId())) {
             addedcommerceItem = commerceItemImpl;
         }
    }

    不知道有没有看出来其他可改进的地方?④“commerceItemImpl.getCatalogId() != null”其实没有必要进行非空判断,这里的非空判断主要是对下面的equal()方法做准备,而Objects.equals()方法可以减少非空判断这一步骤。⑤另外,if的判断语句过长可读性差,可以将判断语句的结果赋值给临时变量更好。
    corrected3:

            for (Object commerceItem : commerceItems) {
                if (!(commerceItem instanceof NGPCommerceItemImpl)) {
                    continue;
                }
                NGPCommerceItemImpl commerceItemImpl = (NGPCommerceItemImpl) commerceItem;
                boolean isValidOfCatalogRefId = commerceItem != null &&
                Objects.equals(commerceItemImpl.getCatalogRefId(), addItems[0].getCatalogRefId());
                if (isValidOfCatalogRefId) {
                    addedcommerceItem = commerceItemImpl;
                }
            }

    2)不知所谓的代码

    maxqty 被定义为局部变量,实际上却是个常量,后面的代码没有对其进行修改,这里应将其定义为静态常量。
    数组details到底是啥,我将方法读完后都它不知道是什么东西,应该取一个更长具有描述性的变量名。

                    int maxqty = 999;
                    Object[] details = new Object[2];
                    details[0] = maxqty;
                    //.....省略后面的代码
                    

    3)判断条件错误

    条件明显写反了,如果result 为null,if块内的代码会执行,那么代码
    "result.getError(InternationalTools.RESTRICTION_ERROR_CODE).toString()"一定会出现空指针异常!
    origin:

                if (result == null || result.hasErrors()) {
                    String errMessageKey = result.getError(InternationalTools.RESTRICTION_ERROR_CODE).toString();
                   //.......省略若干代码
                    }

    corrected:

                if (result != null && result.hasErrors()) {
                    String errMessageKey = result.getError(InternationalTools.RESTRICTION_ERROR_CODE).toString();
                   //.......省略若干代码
                    }

    4)条件合并:

    origin:

                String currentId = pRequest.getParameter(commerceItem.getId());
                if (StringUtils.isNotBlank(currentId)) {
                    if (commerceItem instanceof GCNGPLessonsCommerceItemImpl) {
                        if (Long.parseLong(currentId) != commerceItem.getQuantity()) {
                            vlogError("preSetOrderByCommerceId() Lessons quantity can not be changed to:{0}", currentId);
                            addFormException(new DropletException(UserMessage.format(UserMessageKeys.KEY_VALIDATION_QUANTITY_FORMAT, new Long[]{new Long(1)}, pRequest.getLocale())));
                        }
                    }
                }

    多个连续的if语句可以用“&&”或“||”减少if块的圈层数,使代码更整齐。
    corrected:

                boolean isIncorrectQuantity = StringUtils.isNotBlank(currentId) && (commerceItem instanceof GCNGPLessonsCommerceItemImpl)
                    && Long.parseLong(currentId) != commerceItem.getQuantity();
                if (isIncorrectQuantity) {
                    vlogError("preSetOrderByCommerceId() Lessons quantity can not be changed to:{0}", currentId);
                    addFormException(new DropletException(UserMessage.format(UserMessageKeys.KEY_VALIDATION_QUANTITY_FORMAT, new Long[]{new Long(1)}, pRequest.getLocale())));
                }

    5)无用的代码

    “getFormError()”为只读方法(只读方法的唯一作用是获取返回值),方法本身不会改变某些对象的行为、无副作用。“getFormError()”的返回值又只用来做条件判断,if块内只有“return”一条语句,,而if块已经到方法底部,不管其返回值如何都会结束“xxx()”方法.

    public void xxx(){
            //.....省略前面的代码
            if (getFormError()) {
                return;
            }
        }


  • 相关阅读:
    项目质量管理
    项目成本管理
    项目进度管理
    项目范围管理
    项目整体管理
    项目立项管理
    信息系统项目管理基础
    信息化和信息系统
    linux(3)
    Patorjk
  • 原文地址:https://www.cnblogs.com/gocode/p/part01-refactoring-to-improve-code-quality.html
Copyright © 2020-2023  润新知