重构手法之在对象之间搬移特性【3】
本小节目录
5Hide Delegate(隐藏“委托关系”)
概要
客户通过一个委托关系来调用另一个对象。
在服务类上建立客户所需的所有函数,用以隐藏委托关系。
动机
如果某个客户先通过服务对象的字段或者属性得到另一个对象,然后调用后者的函数,那么客户就必须知晓这一层委托关系。万一委托关系发生变化,客户也得相应变化。你可以在服务对象上放置一个简单的委托关系,将委托关系隐藏起来,从而去除这种依赖。这么一来,即便将来发生委托关系上的变化,变化也将被限制在服务对象中,不会波及客户。
范例
看下面代表“人”的Person类和代表“部门”的Department类:
class Person { public Department Department { get; set; } }
class Department { private string _chargeCode; public Person Manager { get; set; } public Department(Person manager) { Manager = manager; } }
如果客户想知道某人的经理是谁,他必须先取得Department对象:
Person john = new Person(); var manager = john.Department.Manager;
这样的编码就对客户揭露了Department的工作原理,于是客户知道:Department用以追踪“经理”这条消息。如果对客户隐藏Department,可以减少耦合。为此,我们在Person中建立一个简单的委托函数:
class Person { public Department Department { get; set; } public Person GetManager() { return Department.Manager; } }
现在,我得修改Person的所有客户,让它们改用新函数:
Person john = new Person(); var manager = john.GetManager();
修改完所有的客户之后,就可以将Person的Department的get设为私有的了。
public Department Department { private get; set; }
当然了也可以将属性改为私有字段:
private Department _department;
小结
“封装”即使不是对象的最关键特征,也是最关键特征之一。“封装”意味着对象都应该尽可能少了解系统的其他部分。如此一来,一旦发生变化,需要了解这一变化的对象就会较少。
6Remove Middle Man(移除中间人)
概要
某个类做了过多的简单委托动作。
让客户直接调用委托类。
动机
第5节我们说到“封装受托对象”的好处。但是这样的封装也是要付出代价的,即:每当客户要使用受托类的新特性时,就必须在服务端添加一个简单委托函数。随着受托类的特性越来越多,这一过程将非常痛苦。服务类完全成了“中间人”,这时候就需要让客户直接调用受托类。
范例
还是来看上面的“人与部门”的例子。
class Person { public Department Department { private get; set; } public Person GetManager() { return Department.Manager; } }
class Department { private string _chargeCode; public Person Manager { get; set; } public Department(Person manager) { Manager = manager; } }
为了找出某人的经理,客户代码可能这样写:
Person john = new Person(); var manager = john.GetManager();
像这样,使用封装和Department都很简单。但如果大量函数都这么做,就不得不在Person之间安置大量的委托行为。这就是该移除中间人的时候了。
首先在Person中建立一个函数用于获得受托对象:
public Department GetDepartment() { return Department; }
然后逐一处理每个委托函数。针对每一个这样的函数,找出通过Person使用的函数,并对它进行修改,使它首先获得受托对象,然后直接使用后者:
var manager = john.GetDepartment().Manager;
然后就可以删除Person的GetManager()函数。
小结
很难说什么程度的隐藏才是最合适的。随着系统的变化,“合适的隐藏程度”这个尺度也在相应改变。昨天你感觉恰如其分的封装,今天就可能显得很笨拙。还好,我们有了Hide Delegate和Remove Middle Man,因为我们可以在系统运行过程中不断进行调整。
重构的意义在于:永远不必说对不起——只要把出问题的地方修补好就行了。
To Be Continued……