一个函数,它的参数过多是不好的,不好维护和修改,易读性也差,容易出错。
      消除过长参数的方法,有如下:
       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

Long Parameter List(过长参数列)---要重构的味道的更多相关文章

  1. 【重构】 代码的坏味道总结 Bad Smell (一) (重复代码 | 过长函数 | 过大的类 | 过长参数列 | 发散式变化 | 霰弹式修改)

    膜拜下 Martin Fowler 大神 , 开始学习 圣经 重构-改善既有代码设计 . 代码的坏味道就意味着需要重构, 对代码的坏味道了然于心是重构的比要前提; . 作者 : 万境绝尘 转载请注明出 ...

  2. 重构 之 总结代码的坏味道 Bad Smell (一) 重复代码 过长函数 过大的类 过长参数列 发散式变化 霰弹式修改

    膜拜下 Martin Fowler 大神 , 开始学习 圣经 重构-改善既有代码设计 . 代码的坏味道就意味着需要重构, 对代码的坏味道了然于心是重构的比要前提; . 作者 : 万境绝尘 转载请注明出 ...

  3. C++11变长参数模板

    [C++11变长参数模板] C++03只有固定模板参数.C++11 加入新的表示法,允许任意个数.任意类别的模板参数,不必在定义时将参数的个数固定. 实参的个数也可以是 0,所以 tuple<& ...

  4. shell脚本处理长参数的模板

    shell脚本处理长参数的模板 一个shell模板,处理命令行参数,支持长短参数: #!/bin/bash # # FILE: kvm-clone-v2.sh # # DESCRIPTION: Clo ...

  5. go实例—函数或方法的可变长参数

    支持可变长参数列表的函数可以支持任意个传入参数,比如fmt.Println函数就是一个支持可变长参数列表的函数. 需要注意的是,可变长参数应该是函数定义的最右边的参数,即最后一个参数 package ...

  6. 介绍C++11标准的变长参数模板

    目前大部分主流编译器的最新版本均支持了C++11标准(官方名为ISO/IEC14882:2011)大部分的语法特性,其中比较难理解的新语法特性可能要属变长参数模板(variadic template) ...

  7. Java语法糖初探(三)--变长参数

    变长参数概念 在Java5 中提供了变长参数(varargs),也就是在方法定义中可以使用个数不确定的参数,对于同一方法可以使用不同个数的参数调用.形如 function(T …args).但是需要明 ...

  8. Python的不定长参数研究

     通过观察程序和运行结果我们发现,传参时将1传给了a,将2传给了b,将3,4,5传给了*args,将m=6,n=7,p=8传给了**kwargs.为什么是这样传参呢?*args和**kwargs又是什 ...

  9. C++中的变长参数

    新参与的项目中,为了使用共享内存和自定义内存池,我们自己定义了MemNew函数,且在函数内部对于非pod类型自动执行构造函数.在需要的地方调用自定义的MemNew函数.这样就带来一个问题,使用stl的 ...

随机推荐

  1. Notes of the scrum meeting(12.9)

    meeting time:14:00~17:00p.m.,December 9th,2013 meeting place:一号教学楼209 attendees: 顾育豪                 ...

  2. VS2005、VS2008中的快捷键、组合键大全

    Ctrl+E,D ----格式化全部代码 Ctrl+E,F ----格式化选中的代码 CTRL + SHIFT + B生成解决方案 CTRL + F7 生成编译 CTRL + O 打开文件 CTRL ...

  3. iOS- 用UICollectionViewController 来进行横竖屏九宫格布局

    1.简单说说UICollectionViewController 我们在做九宫格布局时,可以使用UIScrollView,也可以使用UICollectionViewController. 当我们用UI ...

  4. listBox和pictureBox的使用

    重要属性:pictureBox中SizeMode可以更改图像显示的尺寸大小. using System; using System.Collections.Generic; using System. ...

  5. oracle 删除数据恢复

    select *  from taxi_comp_worksheet_ext   as of timestamp to_timestamp('2014-09-22 13:00:00', 'yyyy-m ...

  6. WC2017 划水记

    Day 0 (2.2) 一寒假没有好好写题....于是晚上打了人生第一场codeforces,写了Div2三道水题就弃疗了23333333 Day  1  (2.3) 从德州高铁站坐小火车G57去绍兴 ...

  7. 【bzoj3427】Poi2013 Bytecomputer dp

    题目描述 A sequence of N  integers I1,I2…In from the set {-1,0,1} is given. The bytecomputer is a device ...

  8. python字典的常用操作

    # dic={[1,2,3]:'123'} #可变类型不能当做字典的key,value可以使用任意类型 # dic={(2,3,4):'123'} # print (dic[(2,3,4)]) #元组 ...

  9. Python 源码剖析(五)【DICT对象】

    五.DICT对象 1.散列表概述 2.PyDictObject 3.PyDictObject的创建与维护 4.PyDictObject 对象缓冲池 5.Hack PyDictObject 这篇篇幅较长 ...

  10. Android Bitmap和Drawable互转及使用BitmapFactory解析图片流

    一.Bitmap转Drawable Bitmap bmp=xxx; BitmapDrawable bd=new BitmapDrawable(bmp); 因为BtimapDrawable是Drawab ...