重构-改善既有代码的设计-简化函数调用

Rename Method 函数改名

问题

函数的名称未能揭示函数的用途。
方法
修改函数名称。
动机
好的函数需要有一个清晰的函数名。保证一看就懂
Add Parameter 添加参数
问题
某个函数需要从调用端得到更多信息。
方法
为此函数添加一个对象参数,让该对象带进函数所需信息。
动机
如果发现缺少参数,当然就需要添加参数。但是在添加之前,先思考是否一定要添加。或者实用参数对象
Remove Parameter 移除参数
问题
函数本体不再需要某个参数。
方法
将该参数去除。
动机
别人在调用的时候,面对这个无用的参数可能无所适从
Separate Query from Modifier 将查询函数和修改函数分离
问题
某个函数既返回对象状态值,又修改对象状态。
方法
建立2个不同的函数,其中一个负责查询,另一个负责修改。
动机
首先这个函数做了两件事,就很值得重构了。其次 不光要查询,还要修改。这个函数会成为bug之源。
考虑并发情况
Parameterize Method 令函数携带参数
问题
若干函数做了类似的工作,但在函数本体中却包含了不同的值。
方法
建立一个单一函数,以参数表达那些不同的值。
动机
你可能会发现这样的2个函数:它们做着类似的工作,但因少数几个值致使行为略为不同。这种情况下,你可以将这些各自分离的函数统一起来,并通过参数来处理那些变化,用以简化问题。这样的修改可以去除重复代码,并提高灵活性,因为你可以用这个参数处理更多的变化情况。
Replace Parameter with Explicit Methods 以明确函数取代参数
问题
你有一个函数,其中完全取决于参数值而采取不同行为。
方法
针对该参数的每个可能值,建立一个独立函数。
动机
(以明确函数取代参数)恰恰相反于 (令函数携带参数)。如果某个参数有多种可能的值,而函数内又以条件表达式检查这些参数值,并根据不同参数值做出不同的行为,那么就应该使用本项重构。
Preserve whole object 保持对象完整
问题
你从某个对象中取出若干值,将它们作为某一次函数调用时的参数。
方法
改为传递整个对象。
动机
有时候,你会将来自同一对象的若干项数据作为参数,传递给某个函数。这样做的问题在于:万一将来被调用函数需要新的数据项,你就必须查找并修改对此函数的所有调用。如果你把这些数据所属的整个对象传给函数,可以避免这种尴尬的处境,因为被调用函数可以向那个参数对象请求任何它想要的信息。不过事情总有2面:如果你传的是数值,被调用函数就只依赖于这些数值,而不依赖它们所属的对象。
Replace Parameter with Methods 以函数取代参数
问题
对象调用某个函数,并将所得结果作为参数,传递给另一个函数。而接受该参数的函数本身也能够调用前一个函数。
方法
让参数接受者去除该项参数,并直接调用前一个函数。
动机
如果函数可以通过其他途径获得参数值,那么它就不应该通过参数取得该值。过长的参数列会增加程序阅读者的理解难度,因此应该尽可能缩短参数列的长度。
Introduce Parameter Object 引入参数对象
问题
某些参数总是很自然地同时出现。
方法
以一个对象取代这些参数。
动机
本项重构还可以带给你更多好处。当你把这些参数组织到一起后,往往很快可以发现一些可被移至新建类的行为。通常,原本使用那些参数的函数对这一组参数会有一些共通的处理,如果将这些共通行为移到新对象中,你可以减少很多重复代码。
Remove setting Method 移除设置函数
问题
类中的某个字段应该在对象创建时被设值,然后就不再改变。
方法
去掉该字段的所有设值函数。


动机
如果你为某个字段提供了设值函数,这就暗示这个字段值可以被改变。如果你不希望在对象创建之后此字段还有机会被改变,那就不要为它提供设值函数。这样你的意图会更加清晰,并且可以排除其值被修改的可能性。
如果你保留了间接访问变量的方法,就可能经常有程序员盲目使用它们。这些人甚至会在构造函数中使用设值函数。
Hide Method 隐藏函数
问题
有一个函数,从来没有被其他任何类用到。
方法
将这个函数修改为private。
动机
重构往往促使你修改函数的可见度。提高函数可见度的情况很容易想象:另一个类需要用到某个函数,因此你必须提高该函数的可见度。但是要指出一个函数的可见度是否过高,就稍微困难一些。理想状态下,你可以使用工具检查所有函数,指出可被隐藏起来的函数。即使没有这样的工具,你也应该时常进行这样的检查。
   一种特别常见的情况是:当你面对一个过于丰富、提供了过多行为的接口时,就值得将非必要的取值函数和设值函数隐藏起来。尤其当你面对的是一个简单封装的数据容器时,情况更是如此。随着越来越多行为被放入这个类,你会发现许多设值/取值函数不再需要被公开,因此可以将它们隐藏起来。如果你把取值/设值函数设为private,然后在所有地方都直接访问变量,那就可以放心移除取值/设值函数了。
Replace Constructor with Factory Method 以工厂函数取代构造函数
问题
你希望在创建对象时不仅仅是做简单的建构动作。
方法
将构造函数替换为工厂函数。
动机
就是在派生子类的过程中以工厂函数取代类型码。你可能常常需要根据类型码创建相应的对象,现在,创建名单中还得加上子类,那些子类也是根据类型码来创建。然而由于构造函数只能返回单一类型的对象,因此你需要将构造函数替换为工厂函数。
   此外,如果构造函数的功能不能满足你的需要,也可以使用工厂函数代替它。工厂函数也是Change Value to Reference (将值对象改为引用对象)的基础。你也可以令你的工厂函数根据参数的个数和类型,选择不同的构建行为。
Encapsulate Downcast 封装向下转型
问题
某个函数返回的对象,需要由函数调用者执行向下转型(downcast)。
方法
将向下转型动作移到函数中。


动机
向下转型也许是无法避免的,但你仍然应该尽可能少做。如果你的某个函数返回一个值,并且你知道所返回的对象类型比函数签名所昭告的更特化,你便是在函数用户身上强加了非必要的工作。这种情况下你不应该要求用户承担向下转型的责任,应该尽量为他们提供准确的类型。
以上所说的情况,常会在返回迭代器或集合的函数身上发生。此时你就应该观察人们拿这个迭代器干什么用,然后针对性地提供专用函数。
Replace Error Code with Exception 以异常取代错误码
问题
某个函数返回一个特定的代码,用以表示某种错误情况。
方法
改用异常。
动机
可以使用更好的错误处理方式:异常。它清楚地将“普通程序”和“错误处理”分开了,这使得程序更容易理解:代码的可理解性应该是我们追求的目标。
Replace Exception with Test 以测试取代异常
问题
面对一个调用者可以预先检查的条件,你抛出一个异常。
方法
修改调用者,使它在调用函数之前先做检查。
动机
异常的出现是程序语言的一大进步。但是,就像许多好东西一样,异常会被滥用,从而变得不再让人愉快。“异常”只应该被用于异常的、罕见的行为,也就是那些产生意料之外的错误的行为,而不应该成为条件检查的替代品。如果你可以合理期望调用者在调用函数之前检查某个条件,那么就应该提供一个测试,而调用者应该使用它。
Java架构师之路:https://jq.qq.com/?_wv=1027&k=5B436TY
上一篇:源代码控制VisualSVN Server的配置和使用方法


下一篇:C++中类成员函数指针详解