Bad Smells in Codes

1. Duplicated Code(重复代码)
现象:重复代码是最常见的Bad Smells. 如果在程序中多次出现重复的代码结构,就应该设法去重构它们。
策略:相同的类的重复代码通过Extract Method方法进行重构;在不同Subclasses中:通过Extract Method提炼出重复的代码,然后通过Pull Up Method将该方法移动到上级的Super class内;在没有关系的Classes中:通过对其中一个使用Extract Class将重复的代码提炼到一个新类中,然后在另一个Class中调用生成的新类,消除重复的代码

2. Long Method(过长的Method)
现象:过长的代码会使得Method难以理解和维护,应该将该Method分解成多个独立功能的Method。
策略:通过Extract Method方法分解长Method。一个Method应该只用一个独立的意图

3. Large Class(庞大的类)
现象:单一类做过多的事情
策略:使用Extract Class方法。提炼每个使用方式的接口有助于了解整个类结构

4. Long Parameter List(过长的参数列表)
现象:一个Method中传入过长的参数列表,使得参数列难以理解。修改参数列时将会使得参数前后不一致
策略:如果可以通过向已存在的对象查询获取参数,则可通过Replace Parameter with Method,移除参数列,通过在Method内部向上述已存在的对象查询来获取参数;如果参数列中若干参数是已存在对象的属性,则可通过Preserve Whole Object将这些参赛替换为一个完整对象;还可以将若干不相关的参数,使用Introduce Parameter Object来创建一个新的参数类。

5.Divergent Change(发散式变化)
现象:某个类因为外部需求的改变而需要进行不同的修改。例如:加入新的数据库,不得不修改类中的3个Method
策略:将每次因同一条件变化,而需要同时修改的若干方法通过Extract Class将它们提炼到一个新Class中。实现目标是:每次变化需要修改的方法都在单一的Class中,并且这个新的Class内所有的方法都应该与这个变化相关。

6.Shotgun Surgery(霰弹式修改)
现象:相似于Divergen Change, 但是恰恰相反。当发生某一的改变时,需要同时修改多个不同的类。这种情况下,可能会漏掉一些重要的改动。
策略:使用Move Method和Move Field方法将所有的变化集中到一个Class中。如果没有合适的Class,则创建一个新Class。
Divergent Change是一个类会发生多个变化, 而Shotgun Surgery则是一个变化需要改变多个类. 这两个方式都是要使得变化和修改类是一对一的关系

7.Feature Envy(依恋情结)
现象:一个类中的Method操作了另一个类的数据。
策略:对象的要点在于:"将数据和操作行为(方法)封装在一起"。Method应该放在它所操作的数据所在的类内。使用Move Method将这些方法移动到对应的Class中。

8.Data Clumps(数据泥团)
现象:多个相关的数据项多次出现在类的域、Method的参数列表中。应该创建新的对象取代这些相同的域或参数列表。
策略:通过使用Introduce Parameter Object(创建新的参数对象取代这些参数)或Preserve Whole Object(使用已存在的对象取代这些参数),实现使用对象代替Class成员变量和方法中参数列表。

9.Primitive Obsession(基本数据类型的困惑)
现象:对象的初学者常常难以使用对象。例如用数字和利率来表示Money类,用上限和下限表示Range类,又或者是用类来表示一些特殊的数据如电话号码和邮政编码等。
对个别的数据用Replace Data Value with Object将单独的数据替换为对象;如果数据是type code(如枚举类型)并且它的值不会影响行为,使用Replace Type Code with Class方法将类型替换为类;如果某些条件(如Switch语句)依赖于type code使用Replace Type Code with Subclasses或者Replace Type Code with State/Strategy来消除type code.

10.Switch Statements(Switch语句)
现象:同样的Switch语句出现在不同的方法或不同的Class中,这样当需要增加新的CASE分支或者修改CASE分支内语句时,就必须找到所有的地方,然后进行修改。
策略:许多时候,应该考虑多态来替换Switch模块。首先使用Extract Method将Switch语句提炼到一个独立的Method。用Move Method搬移到需要多态性(Polymorphism)类。再考虑是否使用Replace Type Code with Subclasses或者Replace Type Code with State/Strategy构造继承关系。使用Replace Conditional with Popymorphism用多态替换条件。
注意:并不是所有的Switch都应该用多态替换。如果单一的Method中的Switch语句,用多态替换Switch将会是大材小用,而且是不必要的。

11.Parallel Inheritance Hierarchies(平行继承体系)
现象:Parallel Inheritance Hierarchies是Shotgun Surgery的一个特例。在继承体系中,为某个class增加一个subclass时,也必须为另一个class相应增加一个subclass。
策略: 重构的策略是:"一个类层次的实例引用另一个类层次的实例"。运用Move Method和Move Field将被引用class中的一些方法和成员变量迁移宿主class中,消除被引用class的继承体系。

12.Lazy Class(多余类)
现象:某一些class由于种种原因,现在已经不再承担足够责任,有些多余了
策略:通过Collapse Hierarchy,将这些冗余的class合并到superclass或subclass中,或者通过Inline Class(与Extract Class相反),将这些冗余class中的所有Method/Field迁移到其他相关的class中。

13.Speculative Generality(投机的预见性设计)
现象:系统中出现一些无用的abstract class,或者非必要的delegation(委托),或者多余的参数等等。
策略:分别使用Collapse Hierarchy合并abstract class,使用Inline Class移除非必要的delegation,使用Remove Parameter删除多余的参数。

14.Temporary Field(临时域)
现象:class中存在一些Field,这些Field只在特定的环境下才会设置。例如,一个算法需要多个value,这些value不是通过Method参数传递,而是同过Field传值。
策略:通过Extract Class将这些Field及操作这些Field的Method移植的一些新的Class中。

15.Message Chains(过度耦合的消息链)
现象:向一个对象请求另一个对象,然后再向后者请求另一个对象,……,这就是Message Chain,意味着Message Chain中任何中间环节的改变,将导致Client端不得不修改。
策略:找出终端链对象的用途,尝试使用Extract Method方法将该部分代码分离出来,再用Move Method方法将链表去除。

16.Middle Man(中间转手人)
现象:Class中过多的Method都委托给其他class。也就是说A对象需要调用C对象的方法,必须先通过B对象来调用C对象的方法。
策略:使用Remove Middle Man方法让A对象直接调用C对象的方法。剩下的B对象的一部分Method做比较少的事情,用Inline Method方法将这些Method内嵌到A Class中;如果这些Method做额外的事情,则使用Replace Delegation with Inheritance将中间对象变为真实对象的子类。

17.Inappropriate Intimacy(不正当的访问关系)
现象:两个Class过分亲密,试图访问对方的私有部分的域和方法。这种不正当的关系需要消除。
策略:可以采用Move Method和Move Field来帮助他们划清界限,减少他们之间亲密行为。尝试使用Change Bidirectional Association to Unidirectional,双向的互相访问改为单向访问。或者通过Extract Class将两个Class之间的共同点移植到一个新的Class中。
继承常常会导致为overintimacy, 子类通常想了解父类的隐藏实现。考虑Replace Delegation with Inheritance用托管替代继承。

18.Alternative Classes with Different Interfaces(类可选的不同接口)
现象:两个不同signature的Method做同一的事情。
策略:使用Rename Method,根据他们的用途来重命名。另外,可以适当运用Move Method迁移某些行为,使Classes的接口保持一致。

19.Incomplete Library Class(不完美的程序库类)
现象:Library Class(类库)设计不是很完美,我们需要添加额外的方法。
策略:如果可以修改Library Class的Source Code,直接修改最好。如果无法直接修改Library Class,并且只想修改Library Class内的一两个Method,可以采用Introduce Foreign Method策略:在Client Class中建立一个Method,以外加Method的方式来实现一项新功能(一般而言,以server class实例作为该Method的第一个参数)。
如果需要建立大量的额外Method,可应该采用Introduce Local Extension:建立一个新class,使它包含额外Method,并且这个class或者继承或者wrap(包装)source class。

20.Data Class(纯数据类)
现象:Class只有fields或get/set属性,没有任何行为。
策略:找出其他class中访问Data Class中的getter/setter的Method,尝试以Move Method将这些Method移植到Data Class中,实现将数据和操作行为(方法)包装在一起,也让Data Class承担一定的责任(方法)。

21.Refused Bequest(拒绝继承)
现象:子类不需要继承父类的一些不必要Method和Field。
策略:为subclass新建一个兄弟(sibling class),再运用Push Down Method和Push Down Field将superclass中的子类不需要继承的Method和Field下推到兄弟class,这样superclass就只包含subclass共享的东西了。其实,也就是将superclass中一些与特定的Method和Field放到特定的subclass中,superclass中仅包含subclass共享的Method和Field。即父类应该是抽象的,它仅用来提供接口。

如果不想修改superclass,还可以运用Replace Inheritance with Delegation来达到目的。也就是以委托取代继承,在subclass中新建一个Field来保存superclass对象,去除subclass对superclass的继承关系,委托或调用superclass的方法来完成目的。

22.Comments(过多的注释)
现象:注释过多意味着该段代码难于理解。
策略:通过上面提及的各种重构策略,将代码的坏味道去除,使注释变成多余。
如果需要注释/解释一段代码做了什么,则可以试试Extract Method,提取出一个独立的Method,让Method名称解释该Method的用途/功能。另外,如果觉得需要注释来说明系统的某些假设条件,也可尝试使用Introduce Assertion(引入断言),来明确标明这些假设。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值