• Long Parameter List(过长参数列)---要重构的味道


      一个函数,它的参数过多是不好的,不好维护和修改,易读性也差,容易出错。
          消除过长参数的方法,有如下:
           1.在面向对象中,你可以传递一个对象给函数,函数通过访问对象来获得参数。也就是,对象里面了包含参数需要的多个参数。
           2.函数通过访问函数所在类的成员变量,或者其它函数来获取原来要传入的参数。因为,有时候,是可以自己通过宿主类来获取需要的值,而不需要外部传入。
     
           但是,并不是在任何情况下,都包装所有参数到一个对象中。有时候,是反过来,把参数从对象中拆解出来,因为,你不想要对象间的依赖。
     
     
          相应的重构手法:
     
          Replace Parameter with Method(用函数取代参数)
     
           手法的含义:对象调用某个函数,并将所得结果作为参数,传递给另一个函数。而接受该参数的函数本身也能够调用前一个函数。那么,让参数接受者去除该项参数,并直接调用前一个函数。
          例子:
           public double getPrice() {
           int basePrice = _quantity * _itemPrice;
           int discountLevel;
           if (_quantity > 100) discountLevel = 2;
           else discountLevel = 1;
           double finalPrice = discountedPrice (basePrice, discountLevel);
           return finalPrice;
       }
    
       private double discountedPrice (int basePrice, int discountLevel) {
           if (discountLevel == 2) return basePrice * 0.1;
           else return basePrice * 0.05;
       }
    
            应用Replace Parameter with Method手法,重构后,结果是:将discountLevel参数消除掉,通过在函数体内添加参数值获取函数来实现。
             public double getPrice() {
           return discountedPrice ();
       }
    
       private double discountedPrice () {
           if (getDiscountLevel() == 2) return getBasePrice() * 0.1;
           else return getBasePrice() * 0.05;
       }
    
       private double getBasePrice() {
           return _quantity * _itemPrice;
       }
    
      
     
         Preserve Whole Object(保持对象完整)
         手法的含义:你从某个对象中取出若干值,将它们作为某一次函数调用时的参数。改为传递整个对象。
         例子:
       
         重构前:
           HeatingPlan方法withinRange(int low, int high)。
           我们的目的是,把这两个参数才为一个,修改为从从一个对象中获取。
      class Room...
        boolean withinPlan(HeatingPlan plan) {
            int low = daysTempRange().getLow();
            int high = daysTempRange().getHigh();
            return plan.withinRange(low, high);
        }
      class HeatingPlan...
        boolean withinRange (int low, int high) {
            return (low >= _range.getLow() && high <= _range.getHigh());
        }
        private TempRange _range;
    
           修改后的效果:从TempRange对象获取值。
          class HeatingPlan...
        boolean withinRange (TempRange roomRange) {
            return (roomRange.getLow() >= _range.getLow() && roomRange.getHigh() <= _range.getHigh());
        }
      class Room...
        boolean withinPlan(HeatingPlan plan) {
            int low = daysTempRange().getLow();
            int high = daysTempRange().getHigh();
            return plan.withinRange(daysTempRange());
        }
    
             再调整一下,因为_range也是一个TempRange类型的对象。在TempRange中添加是否包含范围的方法。
             效果为:
              class HeatingPlan...
        boolean withinRange (TempRange roomRange) {
            return (_range.includes(roomRange));
        }
      class TempRange...
        boolean includes (TempRange arg) {
            return arg.getLow() >= this.getLow() && arg.getHigh() <= this.getHigh(); 
    
        } 
     
         Introduce Parameter Object(引入参数对象)
         
         手法的含义:
         某些参数总是很自然地同时出现。以一个对象取代这些参数。
     
          例子:
           class Account...
        double getFlowBetween (Date start, Date end) {
            double result = 0;
            Enumeration e = _entries.elements();
            while (e.hasMoreElements()) {
                Entry each = (Entry) e.nextElement();
                if (each.getDate().equals(start) ||
                    each.getDate().equals(end) ||
                     (each.getDate().after(start) && each.getDate().before(end)))
                {
                    result += each.getValue();
                }
            }
            return result;
        }
        private Vector _entries = new Vector();
    
      client code... 
    
        double flow = anAccount.getFlowBetween(startDate, endDate); 
     
          参数start,end是成对出现的。可以用一个对象来代替它们
           class DateRange {
        DateRange (Date start, Date end) {
            _start = start;
            _end = end;
        }
        Date getStart() {
            return _start;
        }
        Date getEnd() {
            return _end;
        }
        private final Date _start;
        private final Date _end;
      }
    
           最终修改后,效果如下:
     
           范围确定操作,被迁移到进行范围过程中用到的参数所在的类中。
             class Account...
        double getFlowBetween (DateRange range) {
            double result = 0;
            Enumeration e = _entries.elements();
            while (e.hasMoreElements()) {
                Entry each = (Entry) e.nextElement();
                if (range.includes(each.getDate())) {
                    result += each.getValue();
                }
            }
            return result;
        }
    
      class DateRange...
        boolean includes (Date arg) {
            return (arg.equals(_start) ||
                    arg.equals(_end) ||
                     (arg.after(_start) && arg.before(_end)));
        }


    参考资料:
    https://sourcemaking.com/refactoring/preserve-whole-object
    https://sourcemaking.com/refactoring/replace-parameter-with-method
    https://sourcemaking.com/refactoring/introduce-parameter-object
  • 相关阅读:
    洛谷 P2616 [USACO10JAN]购买饲料II Buying Feed, II
    洛谷 P3654 First Step (ファーストステップ)
    洛谷 P1223 排队接水
    洛谷 【P1252】马拉松接力赛
    codevs 4927 线段树练习5
    洛谷 P1678 烦恼的高考志愿
    初识 线段树
    开学第一测
    洛谷 P1531 I Hate It
    CSS3 过渡
  • 原文地址:https://www.cnblogs.com/ttylinux/p/4575307.html
Copyright © 2020-2023  润新知