在对象的设计过程中,“[color=red]决定把责任放在哪儿[/color]”即使不是最重要的事,也是最重要的事之一。常常只需要使用[color=red]Move method和move field[/color]简单地移动对象行为,就可以解决这些问题。如果这两个手法都需要用到,建议先使用move field再使用move method。
[b]类往往会因为承担[color=red]过多责任[/color]而变得臃肿不堪[/b]。这时可以使用Extract Class将一部分责任分离出去。如果一个类变得“不负责任”,就使用Inline Class将它融入另一个类。如果一个类使用了另一个类,运用Hide Delegate将这种关系隐藏起来通常是有帮助的。有时候隐藏委托类会导致拥有者的接口经常变化,此时需要使用Remove middle Man。
[b]4.1 move method(搬移函数)[/b]
程序中,有个函数与其所驻类[b]之外[/b]的另一个类进行更多交流,调用后者或被后者调用。就在该函数最常引用的类中建立一个由类似行为的新函数,将旧函数变成一个单纯的委托函数,或是将旧函数完全移除。有时候搬移一组函数比逐个搬移更简单些。
[img]http://dl2.iteye.com/upload/attachment/0107/1543/52007503-c070-3e75-84c4-fe0ab1eefd23.png[/img]
就像图中aMethod()方法老是与Class2交互,那干脆让它们在一起好了。把功能放到Class2中,然后Class1只是直接或间接调用这个方法即可。
[b]4.2 Move field (搬移字段)[/b]
程序中某个[b]字段[/b]被其所驻类[b]之外[/b]的另一个类更多地用到,就可以在目标类新建一个字段,修改源字段的所有用户,令它们改用新字段。
[img]http://dl2.iteye.com/upload/attachment/0107/1545/85fc18cc-8dbc-3c33-a483-444b3fdeffff.png[/img]
在类之间移动状态和行为,是重构过程中必不可少的措施。上述所谓使用可能是通过getter/setter间接进行的。
[b]4.3 Extract Class (提炼类)[/b]
程序中某个类做了应该由两个或更多类做的事,就应该建立一个或多个新类,将相关的字段和函数从旧类搬移到新类。
[img]http://dl2.iteye.com/upload/attachment/0107/1547/b7233330-d528-319f-8509-d329ecc5e001.png[/img]
可以结合move field和move method来达到拆分的目的。[color=red]拆分原则就是单一职责,一个类只做一件事情。[/color]
[b]4.4 Inline Class (将类内联化)[/b]
某个类没有做太多事情,就将这个类所有特性搬移到另一个类中,然后移除原类。
[img]http://dl2.iteye.com/upload/attachment/0107/1549/a0769a1a-c35e-3db8-b758-1e29a16c842e.png[/img]
[b]Inline Class正好与extract class相反[/b]。[b]需要判断要消除的类的语义是否跟要融入的类的语义接近。[/b]
[b]4.5 Hide Delegate (隐藏委托关系)[/b]
客户通过一个委托类来调用另一个对象。在服务类上建立客户所需的所有函数,用以隐藏委托关系。
[img]http://dl2.iteye.com/upload/attachment/0107/1551/5edae5b0-2326-33c1-b612-8c9d326a38e9.png[/img]
“封装”即使不是对象的最关键特征,也是最关键特征之一。“封装”意味着每个对象都应该尽可能少了解系统的其他部分。如此一来,一旦发生变化,需要了解这一变化的对象就会比较少,这会使变化比较容易进行。
[b]如果某个客户先通过服务对象的字段得到另一个对象,然后调用后者的函数,那么客户就必须知晓这一层委托关系,万一委托关系发生变化,客户也得相应变化。[/b]
可以对比4.6的方法,恰当的把握两者的度真的不是那么容易,但我们要知晓,委托和直接调用之间有那么一个“合适的封装和简单的委托”关系。
[b]4.6 Remove Middle Man(移除中间人)[/b]
某个类做了[b]过多的简单委托动作[/b],那就让客户直接调用受委托类,移除中间人。
[img]http://dl2.iteye.com/upload/attachment/0107/1553/5941727e-f676-3c70-b4e9-a22464a345de.png[/img]
在讨论Hide Delegate时我们谈到了“封装受委托对象”的好处。但是这层封装也是要付出代价的,每当客户要使用受委托类的新特性时,就必须在服务端添加一个简单委托函数。随着受委托类的特性越来越多,这一过程会让你痛苦不已。[b]服务类完全变成了一个“中间人”,此时就应该让客户直接调用受托类。[/b]
很难说什么程度的隐藏才是合适的。还好,有了Hide Delegate和Remove Middle man,我们就可以在系统运行过程中不断进行调整。随着系统的变化,“合适的隐藏程度”这个尺度也相应改变。
[b]4.7 Introduce foreign Method (引入外加函数)[/b]
当需要为提供服务的类增加一个函数,但无法修改这个类时(比如是第三方的类),我们可以在客户类中建立一个函数,并以第一参数形式传入一个服务类实例。
[img]http://dl2.iteye.com/upload/attachment/0107/1555/0bbdb547-d468-39f8-9278-2bdac2aef900.png[/img]
[b]4.8 Introduce Local extension (引入本地扩展)[/b]
当需要为服务类提供一些额外函数,但无法修改这个类,可以建立一个新类,使它包含这些额外函数,让这个扩展类称为源类的子类或包装类。
[img]http://dl2.iteye.com/upload/attachment/0107/1557/63979451-9bdc-3174-8299-627823eeb465.png[/img]
这与Introduce foreign method的区别就是需要扩展的方法比较多。[color=red]这也体现了使用组合来代替继承来达到扩展功能的设计思想。[/color]
如果只需要扩展一两个函数,就可以使用Introduce foreign method,但如果需要的额外函数超过两个,外加函数就很难控制了,所以就需要将这些函数组织在一起,放到一个恰当地方去。要达到这一目的,两种标准对象技术:子类化(subclassing)和包装(wrapping)是显而易见的办法,我们把这统称为本地扩展。
[color=red]对比上一篇,如果在一个单独的类中使用extract method等方法已经不能做好内部优化了,那就需要在类之间来做交换或扩展了。[/color]
[b]类往往会因为承担[color=red]过多责任[/color]而变得臃肿不堪[/b]。这时可以使用Extract Class将一部分责任分离出去。如果一个类变得“不负责任”,就使用Inline Class将它融入另一个类。如果一个类使用了另一个类,运用Hide Delegate将这种关系隐藏起来通常是有帮助的。有时候隐藏委托类会导致拥有者的接口经常变化,此时需要使用Remove middle Man。
[b]4.1 move method(搬移函数)[/b]
程序中,有个函数与其所驻类[b]之外[/b]的另一个类进行更多交流,调用后者或被后者调用。就在该函数最常引用的类中建立一个由类似行为的新函数,将旧函数变成一个单纯的委托函数,或是将旧函数完全移除。有时候搬移一组函数比逐个搬移更简单些。
[img]http://dl2.iteye.com/upload/attachment/0107/1543/52007503-c070-3e75-84c4-fe0ab1eefd23.png[/img]
就像图中aMethod()方法老是与Class2交互,那干脆让它们在一起好了。把功能放到Class2中,然后Class1只是直接或间接调用这个方法即可。
[b]4.2 Move field (搬移字段)[/b]
程序中某个[b]字段[/b]被其所驻类[b]之外[/b]的另一个类更多地用到,就可以在目标类新建一个字段,修改源字段的所有用户,令它们改用新字段。
[img]http://dl2.iteye.com/upload/attachment/0107/1545/85fc18cc-8dbc-3c33-a483-444b3fdeffff.png[/img]
在类之间移动状态和行为,是重构过程中必不可少的措施。上述所谓使用可能是通过getter/setter间接进行的。
[b]4.3 Extract Class (提炼类)[/b]
程序中某个类做了应该由两个或更多类做的事,就应该建立一个或多个新类,将相关的字段和函数从旧类搬移到新类。
[img]http://dl2.iteye.com/upload/attachment/0107/1547/b7233330-d528-319f-8509-d329ecc5e001.png[/img]
可以结合move field和move method来达到拆分的目的。[color=red]拆分原则就是单一职责,一个类只做一件事情。[/color]
[b]4.4 Inline Class (将类内联化)[/b]
某个类没有做太多事情,就将这个类所有特性搬移到另一个类中,然后移除原类。
[img]http://dl2.iteye.com/upload/attachment/0107/1549/a0769a1a-c35e-3db8-b758-1e29a16c842e.png[/img]
[b]Inline Class正好与extract class相反[/b]。[b]需要判断要消除的类的语义是否跟要融入的类的语义接近。[/b]
[b]4.5 Hide Delegate (隐藏委托关系)[/b]
客户通过一个委托类来调用另一个对象。在服务类上建立客户所需的所有函数,用以隐藏委托关系。
[img]http://dl2.iteye.com/upload/attachment/0107/1551/5edae5b0-2326-33c1-b612-8c9d326a38e9.png[/img]
“封装”即使不是对象的最关键特征,也是最关键特征之一。“封装”意味着每个对象都应该尽可能少了解系统的其他部分。如此一来,一旦发生变化,需要了解这一变化的对象就会比较少,这会使变化比较容易进行。
[b]如果某个客户先通过服务对象的字段得到另一个对象,然后调用后者的函数,那么客户就必须知晓这一层委托关系,万一委托关系发生变化,客户也得相应变化。[/b]
可以对比4.6的方法,恰当的把握两者的度真的不是那么容易,但我们要知晓,委托和直接调用之间有那么一个“合适的封装和简单的委托”关系。
[b]4.6 Remove Middle Man(移除中间人)[/b]
某个类做了[b]过多的简单委托动作[/b],那就让客户直接调用受委托类,移除中间人。
[img]http://dl2.iteye.com/upload/attachment/0107/1553/5941727e-f676-3c70-b4e9-a22464a345de.png[/img]
在讨论Hide Delegate时我们谈到了“封装受委托对象”的好处。但是这层封装也是要付出代价的,每当客户要使用受委托类的新特性时,就必须在服务端添加一个简单委托函数。随着受委托类的特性越来越多,这一过程会让你痛苦不已。[b]服务类完全变成了一个“中间人”,此时就应该让客户直接调用受托类。[/b]
很难说什么程度的隐藏才是合适的。还好,有了Hide Delegate和Remove Middle man,我们就可以在系统运行过程中不断进行调整。随着系统的变化,“合适的隐藏程度”这个尺度也相应改变。
[b]4.7 Introduce foreign Method (引入外加函数)[/b]
当需要为提供服务的类增加一个函数,但无法修改这个类时(比如是第三方的类),我们可以在客户类中建立一个函数,并以第一参数形式传入一个服务类实例。
[img]http://dl2.iteye.com/upload/attachment/0107/1555/0bbdb547-d468-39f8-9278-2bdac2aef900.png[/img]
[b]4.8 Introduce Local extension (引入本地扩展)[/b]
当需要为服务类提供一些额外函数,但无法修改这个类,可以建立一个新类,使它包含这些额外函数,让这个扩展类称为源类的子类或包装类。
[img]http://dl2.iteye.com/upload/attachment/0107/1557/63979451-9bdc-3174-8299-627823eeb465.png[/img]
这与Introduce foreign method的区别就是需要扩展的方法比较多。[color=red]这也体现了使用组合来代替继承来达到扩展功能的设计思想。[/color]
如果只需要扩展一两个函数,就可以使用Introduce foreign method,但如果需要的额外函数超过两个,外加函数就很难控制了,所以就需要将这些函数组织在一起,放到一个恰当地方去。要达到这一目的,两种标准对象技术:子类化(subclassing)和包装(wrapping)是显而易见的办法,我们把这统称为本地扩展。
[color=red]对比上一篇,如果在一个单独的类中使用extract method等方法已经不能做好内部优化了,那就需要在类之间来做交换或扩展了。[/color]