《重构》读书笔记(二)

来源:互联网 发布:移动公司大数据平台 编辑:程序博客网 时间:2024/04/27 15:15

简化函数调用
=================================================================================

1.Rename Method
    修改函数名称,以揭示函数的用途。
    记住:你的代码首先是为人写的,其次才是为计算机写的。
    不好的函数名字是恶魔的召唤,想想过去浪费的时间吧。
2.Add Parameter
    必须注意的是:不使用本重构的时机。除了添加参数外,你常常还有其他选择。只要可能,其他
    选择都比本项『Add Parameter』好,因为它们不会增加参数列的长度。过长的参数列是不好的味
    道,因为很难记住那么多参数,而且长参数列往往伴随着坏味道Data Clumps(数据泥团)。
3.Remove Parameter
    很多人不愿意去除多余参数,他们的如意算盘是,无论如何多余的参数不会引起任何问题,而且
    以后还可能用上它。
    这也是恶魔的召唤。
    函数调用者必须为每一个参数操心该传什么东西进去。如果不去除多余参数,就会让每一个用户
    多操一份心,很不划算。
    多态函数有些不同,可以考虑添加一个新的函数:调用者知道自己调用的是特定的subclass,
    则可以添加新函数,否则应该保持当前的状态。
4.Separate Query from Modifier
    将查询函数和修改函数分离
    适用情形:某个函数即返回对象状态值,又修改对象状态,试着将查询动作和修改动作分开。
    如果某个函数只向你提供一个值,没有任何看得到的副作用(或说连带影响),用户将用的很放心。
 
    规则:任何有返回值的函数,都不应该有看得到得副作用。注意是『看得到』的副作用。
5.Parameterize Method
   令函数携带参数
   若干函数做了类似的操作,但因少数几个值致使动作略有不同。此时就可用一个公用函数来代替
    这些函数,并通过参数来处理那些变化,以简化问题。
    例:
       // 原代码
       void fivePercentRaise(){...}
       void tenPercentRaise(){...}
    
       // 新代码
       void Raise(float percent){...}
6.Replace Parameter with Explicit Methods
   以明确函数取代参数
   如果某个参数有离散取值,而函数内又以条件式检查这些参数值,并根据不同参数值作出不同的反
   应,那么就应该使用本重构。
   主要目的是获得一个清晰的接口。
   如果参数值不会对函数行为有太多影响,则不应该使用该重构。
   该重构与Parameterize Method刚好相反。
7.Preserve Whole Object
   保持对象完整
   有时候,你会将来自同一对象的若干数据作为参数,传递给某函数。这样做的问题在于:万一将来被
   调用函数需要新的数据项,你就必须查找并修改对此函数的所有调用。如果你把这些数据所属的整个对
   象传给函数,则可避免这种情况。
   
    优点:
      使参数列更稳固。
      避免过长的参数列,提高可读性。
    缺点:
      如果传的是对象,则『参数对象』与『被调用函数所在对象』之间,就有了依赖关系。如果这会使
    你的程序依赖关系混乱,就不该使用本重构。
      性能差。可以忽略该缺点,主要应考虑依赖关系。       
8.Introduce Parameter Object
   引入参数对象
  某些参数总是很自然的同时出项,就应该以一个对象来取代这些参数。
  好处:
      缩短参数的长度。
      参数组织在一起之后,往往可以发现一些『可被移至新建class』的行为,可以使用Move Method。
 
   与Preserve Whole Object有些类似,只不过此处需要新建class而已。  
9.Replace Parameter with Methods
    以函数取代参数
    考虑这样的情形:对象调用某个函数A,并将所得结果作为参数,传递给另一个函数B。如果接受该参数
    的函数B也可以(也有能力)调用函数A,则去掉该参数,直接在函数B中调用函数A。  
    解释一下上面所说的『有能力』:函数B能够提供足够参数给函数A。
   
    需要考虑的是,参数的存在是为了将来的弹性。一般情况是先去掉该参数,在必要的时候再添加。
    另外需要考虑的是进行该重构不好的影响。如果带来的好处小于坏处,则不应该重构。
10.Remove Setting Method
    移除设值函数
    最典型地例子就是Delphi中的只读属性。可以避免程序员盲目地使用它们。
11.Hide Method
    隐藏不需要用户知道的细节,将函数改为private或protected。
12.Replace Constructor with Factory Method
     以工厂方法取代构造函数
     你希望在创建对象时不仅仅是对它做简单的建构工作。
       
     说实话,真不明白该项重构有什么作用?书中举的例子看不出这样做有什么好处,反而把子类和基类绑
   在一起了,依赖关系混乱。
13.Encapsulate Downcast
    封装向下转型操作
    尽量避免向下转型,尽量提供准确的型别。
   
  // 原代码
  Object lastReading(){
    return readings.lastElement();
  }
 
  // 新代码
  Reading lastReading(){
    return (Reading)readings.lastElement();
  }


14.Replace Error Code with Exception
   以异常取代错误码
15.Replace Exception with Test
    以测试(检查,if语句)取代异常
    异常只应该被用于异常的、罕见的行为,也就是那些『意料之外』的错误。
   

处理概括关系
=========================================================================================

1.Pull Up Field
    当subclass中有重复(或相近)的值域,应将它们归纳到superclass中去。
2.Pull Up Method
   重复是错误的滋生地。
   最麻烦的一点:被提升的函数可能会引用只出现在subclass中而不出现在superclass中的特性。如果被
   引用的是函数,你可以将该函数也一同提升到superclass,或者在superclass中建立一个抽象函数。在此
   过程中,你可能需要修改某个函数的签名式(Signature),或建立一个委托函数。
   如果两个函数相似但不相同,你或许可以先以Form Template Method构造出相同的函数,然后再提升。
3.Pull Up Constructor Body
   构造函数本体上移
    就是在subclass的构造函数中,调用superclass的构造函数。
4.Push Down Method
5.Push Down Field
6.Extract Subclass
    你发现class中的某些行为只被一部分实体用到,其他实体不需要他们,此时可以考虑使用本重构或使用
  Extract Class。
7.Extract Superclass
8.Extract Interface
9.Collapse Hierarchy
   合并superclass和subclass
10.Form Template Method
     塑造模板函数
     即模板方法设计模式。
11.Replace Inheritance with Delegation
      一开始你继承了一个class,但随后你发现superclass中的许多操作并不适用于subclass。这种情况下,
     你所拥有的接口并未真正反映出class的功能。或者,你可能发现你从superclass中继承了一大堆subclass
     并不需要的数据,抑或你可能发现superclass中的某些protected函数对subclass并没有什么意义。
     此时你应该选择用委托代替继承。具体操作是:将subclass建成与superclass分离的类,然后将其功能
    委托给superclass的实例。
12.Replace Delegation with Inheritance
    你发现自己需要使用『受托class』中『所有』的函数,并且费了很大力气编写极简的请托函数(delegating
    methods), 就应该使用本重构。
   
   
大型重构
===========================================================================================
1.Tease Apart Inheritance
   梳理并分解继承体系
    某个继承体系同时承担两项责任。
    建立两个继承体系,并通过委托关系让其中一个可以调用另外一个。
   
    混乱的继承体系是一个严重的问题,因为它会导致重复代码。
2.Convert Procedural Design to Objects
   将过程化设计转化为对象设计
   将数据记录编程对象,将行为分开,并将行为移入相关对象之中。
3.Separate Domain from Presentaion
    将领域和表述/显示分离
    某些GUIClass中包含了domain logic,将其分离出来,为它们建立独立的domain classes。
    GUIClass调用domain class。
    适当时候可以使用Duplicate Observed Data方法。
4.Extract Hierarchy
    提炼继承体系
    你有某个class做了太多工作,其中一部分是以大量条件式完成的。
    建立继承体系,以一个subclass表示一种特殊情况。
  
  
代码的坏味道
============================================================================================
1.Duplicated Code(重复代码)
2.Long Method(过长函数)
3.Large Class(过大类)
4.Long Parameter List(过长参数列)
5.Divergent Change(发散式变化)
   如果某个class经常因为不同的原因在不同的方向上发生变化,Divergent Change就出现了。
   此时将对象分为几个会更好,这么一来每个对象就可以只因为一种变化而需要修改(Extract class)。
6.Shotgun Surgery(霰弹式修改)
   与Divergent Change恰恰相反。
   如果每遇到某种变化,你都必须在许多不同的class内做出许多小修改以响应之,你所面临的坏味道就是霰弹式修改。
    此时你应该使用Move Field和Move Method将所有需要修改的代码放进同一个class(已存在或新建)。多余的class
  可以使用Inline class方法去掉。
7.Feature Envy(依恋情结)
   函数对某个class的兴趣高过对自己所在class的兴趣。
   应该运用Move Method将该函数移到其最感兴趣的class之中。
 
  有数个精巧的模式破坏了这个规则,Strategy和Visitor。使用这些模式是为了对抗坏味道Divergent Change,
  它们使得你可以轻松修改函数行为。
8.Data Clumps(数据泥团)
    你常常可以在很多地方看到相同的三或四笔数据项:两个classes内的相同值域、许多函数参数列表中相同的参数。
    这些『总是绑定在一起的数据项』应该放进它们自己的对象。
    得到新对象后,你就可以着手寻找Feature Envy, 这可以帮助你指出『可移至新class』中的种种行为。
9.Primitive Obsession(基本型别偏执)
10.Switch Statements
11.Parallel Inheritance Hierachies(平行继承体系)
     每当你为某个class增加一个subclass,必须也为另一个class相应增加一个subclass。如果你发现某个继承体系的
   class名称前缀和另一个继承体系的class名称前缀完全相同,便是闻到了这种坏味道。
    一般策略:让一个继承体系的实体引用另一个继承体系的实体。
12.Lazy Class(冗赘类)
    如果一个class的所得不值其身价,它就应该消失。
13.Speculative Generality(夸夸其谈未来性)
     当有人说『我想我们总有一天需要做这事』并因而企图以各式各样的挂钩和特殊情况来处理一些非必要的事情,这种坏 味道就出现了。
14.Temporary Field(令人迷惑的临时值域)
  有时你会看到这样的对象:其内某个instance变量仅为某种特定情势而设。这样的代码让人不易理解,因为你通常认为
   对象在所有时候都需要它的所有变量。在变量未被使用的情况下猜测当初其设置目的,会让你发疯。
     请使用Extract class给这个可怜的孤儿创造一个家,然后把所有和这个变量相关的代码都放进这个新家。
15.Message Chains(过度耦合的消息链)
     如果你看到用户向一个对象请求(request)另一个对象,然后再向后者请求另一个对象,然后再请求另一个对象...这
   就是Message Chains。
     例:Server.SomeObj.OtherObj.SomeFunc();
    这时应该使用Hide Delegate方法。将其变成Server.SomeFunc();
16.Middle Man(中间转手人)
   某个class接口有一半的函数都委托给其他class,这就是过度委托。
   使用Remove Middle Man方法直接与实责对象打交道。
   如果这些对象还有其他行为,可以运用Replace Delegation with Inheritance方法。
17.Inappropiate Inimacy(狎昵关系)
   有时候你会看到两个class过于亲密,花费太多时间去探究彼此的private成分。
   消除两者过于紧密的关系。
   Move Method、Move Field
   Change Bidirectional Association to Unidirectional
   Extract Class
   Replace Inheritance with Delegation
18.Alternative Classes with Defferent Interfaces
   异曲同工的类
    如果两个函数做同一件事,却有着不同的签名式,请运用Rename Method。然后运用Move Method,或许还有Extract SuperClass
19.Incomplete Library Class(不完美的程序库类)
20.Data Class(纯稚的数据类)
21.Refused Beques(被拒绝的遗赠)
   subclass应该继承superclass的函数和数据,但如果它们不想或不需要继承,又该怎么办呢?
   这意味着继承体系设计错误。
   传统的方法:为这个subclass新建一个兄弟,再运用Push Down Method和Push Down Field把所有用不到的函数推给那兄弟。
  这样一来superclass就只持有subclass共享的东西。但这么做可能会带来不好的味道。
    如果不严重,就不用理睬。
    如果subclass复用了superclass的行为,却又不愿意支持superclass的接口,则可以用委托来处理。
22.Comments(过多的注释)

原创粉丝点击