代码坏味及解决方案(底层重构和设计模式两个方面)

一、Duplicated Code(重复代码)
重构方面:
1. 同一个类的两个函数含有相同表达式:采用Extract Method提炼出重复的代码.然后让两者调用被提炼出的那一段代码

2. 两个互为兄弟的子类含有相同表达式:

① 两者功能几乎相同:先整理相同功能函数(Extract Method),然后使用继承将其推入父类(Pull up Method) 

② 两者并非完全相同:先用Extract Method将相似和差异部分分开,然后使用Form Template Method设计成Template Method 

③ 如果两者的算法不同功能相同:使用Substitute Algorithm替换其中较差的一个.

3. 毫不相关的类:使用Extract Class将两者重复的代码加入到新的类中,然后分别调用新类该函数

模式方面:
1. 通过形成Template Method去除类层次中不同子类里存在明显或微妙的重复.
2. 如果不同之类的方法除了对象创建不同外其他实现方式类似,可以使用Factory Method引入多态创建重构.为使用Template Method做准备

3. 如果有单独的代码处理一个或一组对象,可以考虑Composite替换1/多之分的重构

4. 如果对象处理方式的区别仅接口不同,可以考虑使用Adapter模式.

5. 如果需要特殊处理空字段,而这些特殊处理几乎一致,可以考虑使用Null Object.

二、Long Method(过长函数)
重构方面:

间接层利益:解释、共享、选择能力

1. 函数含有大量的参数和临时变量:

① 使用Replace Temp with Query消除临时变量(使用临时变量的地方用查询函数替代)Introduce Parameter Object (使用对象来合并相关的临时变量)Preserve Whole Object(多次使用同一对象不同变量来查询,用对象代替不同变量),绝招:Replace Method with Mothod Object(使用对象函数替代对象)

2. 条件表达式和循环:

使用Decompose Conditional (分解条件表达式)处理条件表达式

将循环提炼到独立函数中

模式方面:

1. 可以应用组合方法重构将其分解为Composed Method,如果需要将某个信息累加到一个公共变量中,可以考虑使用Collecting Parameter重构

2. 如果函数包含分配和处理大的Switch语句,可以使用Command替换条件调度程序

3. 如果Switch语句从不同接口的许多类收集数据,可以应用将聚集操作搬移至Visitor

4. 如果他包含的算法是通过运行时来选择版本,可以考虑Strategy 替换条件逻辑.

三、Large Class(过大的类)
重构方面:

1. 使用Extract Class将几个相关的变量提炼至新类中.如果新类适合作为子类使用Extract Subclass处理

2. Large ClassGUI,需要将数据和行为移动至独立领域,将牵涉到数据同步的地方使用Duplicate Observed Data.
模式方面:
1. 使用Command模式将不同请求分摊到对应的类中
2. 使用State模式将不同状态的切换分摊到对应类中

3. 使用Interpreter将大量模仿某种语言的代码分摊到小的Interpreter.

四、Long Parameter List(过长参数列)

重构方面:
1. 可以向已有对象发出一条请求就能取代一个参数,应该使用Replace Parameter with Method.

2. 使用Preserve Whole Object将来自同一对象的一堆数据收集起来

3. 当所属参数缺乏对象归属,可使用Introduce Parameter Object 构造参数对象

五、Divergent Change(发散式变化)
重构方面:

修改软件时,希望仅需要修改系统的某点(主要是一个类受多种变化的影响)

使用Extract Class将变与不变的部分分开

六、Shotgun Surgery(散弹式修改)

修改到的类很多.(一种变化牵涉到多个类)

1. 使用Move MethodMove Field把相关的修改放入同一个类中

七、Feature Envy(依恋情结)

函数对某个类的兴趣高过对自己所处类的兴趣.

1. 整个函数都和某个类有依恋:使用Move Method将其移动至合适的地方

2. 函数的某一部分有依恋:先使用Extract Method把这部分提炼到独立的函数并移至合适的地方

八、Data Clumps(数据泥团)

使用Extract Class将数据提炼到独立对象中.然后应用Introduce Parameter ObjectPreserve Whole Object(将字段的对象直接作为参数传递)为其减肥.

九、Primitive Obsession(基本类型偏执)
重构方面:

1. 对于非类型码数据,使用Replace Data Value with Object将数据组装成对象.\

2. 对于类型码数据

① 不影响行为(可以理解成每次生成对象后该类型码就不会改变):使用Replace Type code with Class(将没有类型码分别用类封装)

② 影响行为(可以理解成对象的类型码经常需要切换):使用Replace Type Code with SubClass或者Replace Type Code With State/Strategy加以处理

模式方面:
1. 如果控制对象的状态转换使用基本类型值的复杂条件逻辑,可以使用State

2. 如果控制算法运行的是非常负责的逻辑,而且该逻辑还使用基本类型值,可以考虑Strategy

3. 如果隐式创建了使用基本类型表示的树结构,可以考虑Composite

4. 如果类有大量方法支持多个基本类型值的组合,就有可能存在隐式语言,可以考虑使用Interpreter

十、Switch Statements(Switch 惊悚现身)
重构方面:

这里主要只的是虽然存在各种分类,但是Switch也出现多次的情况
1. 先使用Extract MethodSwitch分离
2. 再使用Move Method将它搬移到需要多态性的类里面
3. 决定使用Replace Type Code with Subclass或者Replace Type code with State/Strategy.
4. 一旦继承结构生成之后,就可以使用Replace Conditional with Polymorphism
如果只是在单一函数中有些选择事例(并不是不同种类状态),就没必要采用上述步骤处理可以使用Replace Parameter with Explicit Methods.处理过程中可能存在NULL Object可以使用Introduce null Object.
模式方面:

1. 考虑使用Command替换条件调度程序将大的分支语句分解成一组Command对象

2. 考虑使用Visitor来将if-else语句使用多态封装到具体操作类中

十一、Parallel Inheritance Hierarchies(平行继承体系)
属于Shotgun Surgery特殊情况.(在两个继承体系中增加其中一个子类,必须也要增加另一个子类)
1. 让集成体系的实例引用另一个集成体系的实例(使用组合而非继承).可以记忆不使用Move MethodMove Field就可以将应用端的继承消匿于无形.

十二、Lazy Class (冗赘类)
重构方面:

随着系统对修改,类的功能变得单薄的不值其身价
1. 使用Collapse Hierarchy,如果是几乎没用的组件,考虑Inline Class
模式方面:

1. 使用内联Singleton重构来替换Singleton模式

十三、Speculative Generality(夸夸其谈未来性)
1. 如果某个抽象类没有太大作用,使用Collapse Hierarchy.对几乎没用的组件使用Inline Class消除.
2. 如果是函数的参数未被用上,可以使用Remove Parameter.
3. 如果函数名称带有多余的抽象意味,应该对它实施Remove Parameter.
4. 如果函数名称带有多余的抽象意味,使用Rename Method

十四、Temporary Field (令人迷惑的暂时字段)
类的某个字段只是局部使用(也有可能是一个算法函数)
1. 使用Extract Class将与该字段相关的抽象出来

十五、Message Chains(过度耦合的消息链)
1. 使用Hide Delegate隐藏中间
2. 或者可以使用Extract Method,在使用Move Method.

十六、Middle Man(中间人)
1. 过度委托:使用Remove Middle 
2. 不干实事:运用Inline Method 将其直接放入调用端.如果其还有其他行为,可以运用Replace Delegation with Inheritance将继承改为委托

十七、Inappropriate Intimacy(押昵关系)
程序员花太多时间探究彼此的private成分.
1. 采用Move MethodMove Field 帮其划定界限.也可以看看能否使用Change Bidirectional Association to Unidirectional让其中一个类对另一个类分离.或者使用Extract Class将重复的部分放入父类,或者使用Hide Delegate通过组合来传递

十八、Alternative Classes with Different Interfaces(异曲同工的类)
重构方面:

同样类似功能的函数,拥有不同的签名
使用Rename Mothod重命名.然后反复运用Move Method将某些行为分离直至签名一致.
模式方面:
如果使用的代码来自第三方库,可以通过使用Adapter统一接口

十九、Incomplete Library Class(不完美的库类)
主要是当初设计库的作者不可能猜测到未来的需求
使用Introduce Foreign Method(对于无法修改源码的情况),Introduce Local Extension 

二十、Data Class(纯挚的数据类)
除了纯的数据和读取设置数据的函数外,没有任何功能的类.叫做Data Class
找出Data Class运用的场景,然后使用Move Method分离函数功能,再使用Extract Method产生一个搬移函数.最后由于外部函数不用调用读取设置.使用HideMethod隐藏set/get

二十一、Refused Bequest(被拒绝的遗赠)
使用组合而非继承来实现.

二十二、Comments(过多的注释)
使用Extract Method提炼出注释的函数,如果还需注释来解释行为可以使用Rename Method .如果你需要注释说明某些系统的需求规格,试试Introduce Asserion

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值