随笔 - 181  文章 - 15  trackbacks - 0
<2007年7月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

常用链接

留言簿(1)

随笔分类

随笔档案

My Tech blog

搜索

  •  

最新评论

阅读排行榜

评论排行榜

现在回到重构--改善既有代码的设计这本书。
3.4Long Parameter List(过长参数列)
如果“向既有对象发出一条请求”就可以取得原本位于参数列上的一份数据,那么你应该激活重构准则Replace Parameter with Method。上述的既有对象可能是函数所属class内的一个值域,也可能是另一个参数。你还可以用 Preserve Whole Object将来自同一对象的一堆数据收藏起来,并以该对象替换它们。如果某些数据缺乏合理的对象归属,可使用Introduce Parameter Object为它们制造出一个“参数对象”。

Replace Parameter with Methods(以函数取代参数)
对象调用某个函数,并将结果作为参数,传递给另外一个函数。而接受该参数的函数也可以(也有能力)调用前一个函数。
动机
如果函数可以通过其它途径(而非参数列)获得参数值,那么它就不应该通过参数取得该值。
缩减参数列的办法之一就是,看看“参数接受端”是否可以通过“与调用端相同的计算”来取得参数携带值。如果调用端通过“其所属对象内部的另一个函数”来计算参数,并在计算过程中“未曾饮用调用端的其它参数”,那么你就应该将这个计算过程转移到被调用端内,从而除去该项参数。如果你所调用的函数隶属另一对象,而该对象拥有一个reference指向调用端所属对象,前面所说的这些也同样适用。
作法
1、如果有必要,将参数的计算过程提炼到一个独立函数中。
2、将函数本体内“对该参数的引用”替换为对“新函数的引用”。
3、每次替换后,修改并测试。
4、全部替换完成后,适用Remove Parameter将该参数去掉。


思考:
确实从实践角度讲,上面这种方法是一种很实用的重构方法。确实是缩减了函数的参数个数,并隐藏了一些中间结果。但是我认为,在应用这个方法的时候,还应当考虑这样两个问题:
1、当中间函数(方法)被隐藏的时候,以这个中间函数的返回值为参数的那个函数名还能够表述自己的用途吗?
2、被修改的那个函数所处的具体语境是什么。因为在面向对象编程的时代,单独去考虑一个函数的情况是很少的。确保这个函数是否处在正确的位置上(如是否处在正确的类中)是必要的。



此间存在一个重要的例外。有时候你明显不希望造成“被调用之对象”与“较大对象”间的某种依存关系。这时候将数据从对象拆解出来单独作为参数,也很合情合理。但是请注意其所引发的代价。如果参数列太长或变化太频繁,你就需要重新考虑自己的依存结构了。

 Introduce Parameter Object(引入参数对象)
某些参数总是很自然的同时出现,以一个对象取代这些参数。
你常会看到特定的一组参数总是一起被传递。可能有好几个函数都使用这一组参数,这些函数可能隶属同一个class,也可能隶属不同的classes。这样一组参数就是所谓的Data Clump(数据泥团)。我们可以运用一个对象包装所有这些数据,再以该对象取代它们。
作法:
1、新建一个class,用以表现你想替换的一组参数。将这个class设为不可变的(不可被修改的,immutable)。
2、编译。
3、针对使用该组参数的所有函数,实施Add Parameter,以上述新建class之实体对象作为新添参数,并将此一参数值设为null。
4、对于Data Clump(数据泥团)中的每一项(在此均为参数),从函数签名式中移除之,并修改调用端和函数本体,令他们都改而通过“新建的参数对象” 取得该值。
5、每除去一个参数,编译并测试。
6、将原先的参数全部除去之后,观察有无适当函数可以运用Move Method搬移到参数对象中。


思考:
现在我有一个函数f,函数定义如下:
public string f(int i,int j,string s)
{
   int newValue=i+j;
   string result=s+":"+newValue.ToString();
   return result;
}
现在我把这三个参数转化为类对象,类名定义为MyParameter
public class MyParameter
    {
        
int _i;

        
public int I
        {
            
get { return _i; }
            
set { _i = value; }
        }
        
int _j;

        
public int J
        {
            
get { return _j; }
            
set { _j = value; }
        }
        
string _s;

        
public string S
        {
            
get { return _s; }
            
set { _s = value; }
        }
        
public MyParameter(int i, int j, stirng s)
        {
            _i 
= i;
            _j 
= j;
            _s 
= s;
        }

    }

然后再我的代码中这样写:
f(new MyParameter(3,2,"Result"));

发现什么问题了吗?
1、好像参数并没有减少,只不过是移动到了构造函数中;
2、你从f参数中将会看不出f中到底需要什么东西(如果参数名称体现了参数的用途的话)。
这说明:
1、虽然这是经典的重构方法,但是不能滥用,在使用的时候要谨慎考虑场景是否合适。
2、注意TDA原理,不要刻意产生太多的中间对象。
3、参数不能随便合并或隐去,要特别注意领域模型,要切合领域模型所表述的意图。
我个人认为可以应用的场景:
就是文中所说的DataRange,即适合于被转换为参数对象的参数列具有通用的含义,并且概念层次比较低。


 

posted on 2007-07-10 22:16 littlegai 阅读(262) 评论(0)  编辑 收藏 引用 所属分类: 我的读书笔记

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理