重构方法之对象之间搬移特性

来源:互联网 发布:kali linux下载 编辑:程序博客网 时间:2024/06/05 21:40

在对象的设计过程中,“决定把责任放在哪儿”即使不是最重要的事情,也是最重要的事情之一。但是往往在一开始,我们并不能作对,在这种情况下,可以运用重构。


一、Move Method(搬移函数)

程序中,有个函数与其所驻类之外的另外一个类进行更多的交流;调用后者,或者被后者调用。

在该函数最常引用的类中建立一个有着类似行为的新函数。将旧函数变成单纯的委托函数,或者将旧函数移除。


动机

“搬移函数”是重构理论的支柱。如果一个类有太多行为,或如果一个类与另外一个类有太多合作而形成高多耦合,我就会搬移函数;通过这种手段,可以使系统中的类更加简洁,这些类也会更加干净利落的实现系统赋予的任务。



做法:

  • 检查源类中被源函数所使用的一切特性(包括字段和函数),考虑它们是否也该被搬走。
如果某个特性只是被打算搬移的函数应到,就应该将它一并搬移。如果另有其他函数用到这个特性,你可以考虑将使用该特性的所有函数都搬移,有时候搬移一组函数更简单。
  • 检查源类的超类和子类,看看是否有该函数的其他声明。
如果出现其他声明,你或许无法进行搬移,除非目标类也同样表现出多态
  • 在目标类中声明这个函数
可以为此函数选择一个新名称----------对目标类更有意义的名称
  • 将源函数的代码复制到目标函数中。调整后者,使其能够在新家中正常运行
如果目标函数使用了源类中的特性,你得决定如何从目标函数引用源对象,如果目标类中没有相应的引用,就把源对象的应用当作参数,传给新建的目标函数
如果源函数包含异常处理,要判断异常该由谁来处理。
  • 决定如何从源函数正确引用目标对象
方法1:在源对象中建立一个字段保存目标对象
方法2:寻找源类中的方法或者字段,看哪能否能到目标对象
  • 如果要移除原函数,请将源类中所有对原函数的调用都替换成对目标函数的调用


示例

class  Account...

double overdraftCharge(){

if(_type.isPremium){

double result = 10;

if(_daysOverdrawn > 7) result += (_daysOverdrawn) * 0.85;

return result;

}else

return _daysOverdrawn * 1.75;

}


double bankCharge(){

double result = 4.5;

if(_daysOverdrawn > 0) result += overdraftCharge();

return result;

}

private AccountType _type;

private int _daysOverdrawn;

}




二、Move Field(搬移字段)

程序中,某个字段被其所驻类之外另一个类更多的用到

在目标类中新建一个字段,修改源字段的所有用户,令他们改用新字段


动机

让设计更合理



做法

  • 如果字段的访问权限是public,则使用Encapsulate Field将它封装起来
  • 在目标类中建立相同的字段,并建立get/set方法
  • 决定在源对象中如何引用目标对象
  • 删除源字段,且把所有对源对象的调用替换成对目标函数的调用




三、Extract Class(提炼类)
某一个类做了应该由两个类做的事儿,建立一个新类,将相关的字段从旧类中搬移到新类中


动机
  • 一个类应该十一个清晰的抽象,处理一些明确的责任。
但是往往随着业务复杂度增强,会在这儿增加一些功能,在那儿增加一些功能,这样类就会变得异常复杂,这时就要重构,让类职责明确,提炼新类。
  • 另一种情况,在开发的后期出现一个类由于初始化不同而表现不同。
如果发现子类化只是影响类的部分特性,或如果你发现某些特性需要一种方式来子类化,而某些特性则需要另外一种子类化,这就意味着你需要分解原来的类了。


做法
  • 决定如何划分分解类的责任
  • 建立一个新类,用以表现从旧类中分离出来的责任
如果旧类剩下的责任与旧类的名称不符,就为旧类更名
  • 建立从旧类到新类的访问连接关系
  • 使用Move Field 和 Move Method 
  • 精简类和接口。




四、Inline Class(将类内联化)
某一个类没有做太多的事,将这个类移到另一个类中。

动机
与Extract Class相反,Inline Class是如果一个类不再承担足够的责任,就不再需要存在的理由


做法
  • 在新类中声明源类的public协议,并将其中所有的函数委托至源类
  • 修改所有源类的引用点,改而引用目标类
  • 将源类的所有特性都搬移到新类中


五、Hide Delegate(隐藏“委托关系”)
客户通过一个委托类来调用另一个对象,在服务类上建立客户所需要的所有函数,用以隐藏委托关系

动机
  • “封装”即使不是对象的最关键特征,也是最关键特征之一。
  • 通过委托函数将委托关系隐藏起来,让客户只和服务对象交互,从而消除客户直接接触委托对象。


做法
  • 对于每一个委托中的函数,在服务对象端建立一个简单的委托的函数
  • 调整客户,令它只调用服务对象提供的函数
  • 将来如果没有任何客户端调用委托行为,就可以删除委托函数



六、Remove Middle Man(移除中间人)
某个类做了过多的简单委托动作,那就让客户直接调用受托类把


动机
去掉不必要的委托接口



七、Introduce Foreign Method(引入外加函数)
需要为服务类增加一个函数,但是无法修改服务类;在客户类中建立一个函数,并以第一参数形式传入一个服务类实例。


示例
Date newStart = new Date(preiousEnd.getYear(),preiousEnd.getMonth(),preiousEnd.getDate()+1)

Date newStart = new nextDate(preiousEnd)
private static Date nextDay(Date arg){
return new Date(arg.getYear(),arg.getMonth(),arg.getDate()+1)
}

这是没有办法的办法,最好还是服务类中加入需要的接口。



八、Introduce Local Extension(引入本地扩展)

需要为服务类提供一些额外的函数,但你无法修改这个类,建立一个新类,使它包含这些扩展,让扩展新类成为源类的子类或者包装类。

0 0
原创粉丝点击