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
原文地址:https://www.cnblogs.com/ttylinux/p/4575307.html