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

 

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;
        }
    }

 



posted @ 2019-12-26 10:38  蜀中孤鹰  阅读(203)  评论(0编辑  收藏  举报