重构改善既有代码设计--重构手法14:Hide Delegate (隐藏委托关系)

客户通过一个委托类来调用另一个对象。
在服务类上建立客户所需的所有函数,用以隐藏委托关系。

动机:
封装即使不是对象的最关机特性,也是最关机特性之一。“封装”意味着每个对象都应该少了解系统的其他部分。如此以来,一旦发生变化,需要了解这一变化的就比较少---这会使系统比较容易进行。

任何学过对象技术的人都知道:虽然Java将字段声明为public,但你还是应该隐藏对象的字段。随着经验日渐丰富,你会发现,有更多可以(值得)封装的东西。
如果某个客户需要通过服务对象的字段得到另一个对象,然后调用后者的函数,那么客户就必须知晓这一层委托关系。万一委托关系发生变化,那么客户也得相应变化。你可以在服务对象上放置一个简单的委托函数,将委托关系隐藏起来,从而去除这种依赖。这么以来即使将来发生魏国关系上的变化,变化也将被限制在服务对象中,不会波及客户。

范例:
本例从两个类开始:代表“人”的Person类和代表“部门”的Department类。
class Person{
Department _department;
public Department getDepartment(){
reutrn _department;
}
public void setDepartment(Department department){
_department=department;
}
}

class Department{
private String _chargeCode;
private Person _manager;
public Department(Person manager){
_manager=manager;
}
public Person getManager(){
return _manager;
}
}
..............
如果客户需要知道某一个人的经理是谁,他必须先取得Department对象:
manager=john.getDepartment().getManager();
这样编码就对客户暴露了Department的工作原理,于是客户知道,Department用于追踪“经理”这条信息。如果对客户隐藏Department,可以减少耦合。为了这一目的,
可以在Person类中建立一个简单的委托函数:
public Person getManager(){
return _department.getManager();
}
现在,修改Person的所有客户,让他们改用新函数:
manager=john.getManager();
只要完成了对Department所有函数的委托关系,并修改了相应Person的所有客户,那么就可以移除Person中的访问函数getDepartment()了。

时间: 2024-08-01 10:43:35

重构改善既有代码设计--重构手法14:Hide Delegate (隐藏委托关系)的相关文章

重构改善既有代码设计--重构手法15:Remove Middle Man (移除中间人)

某个类做了过多的简单委托动作.让客户直接调用受托类. 动机:在Hide Delegate (隐藏委托关系)的“动机”中,谈到了“封装委托对象”的好处.但是这层封装也是要付出代价的,它的代价是:每当客户要使用受托类的新特性时,你就必须在服务端添加一个简单委托函数.随着委托类的特性(功能)越来越多,这一过程让你痛苦不已.服务类完全变成了“中间人”,此时你就应该让客户直接调用受托类. 很难说什么程度的隐藏才是合适的.还好,有了Hide Delegate (隐藏委托关系)和Remove Middle M

重构改善既有代码设计--重构手法05:Introduce Explaining Variable (引入解释性变量)

  发现:你有一个复杂的表达式. 解决:将该复杂的表达式(或其中的部分)的结果放进一个临时变量,并以此变量名称来解释表达式用途. //重构前 if((platform.toUpperCase().indexOf("MAC") > -1) && (browser.toUpperCase().indexOf("IE") > -1) && wasInitialized() && resize > 0) {

重构改善既有代码设计--重构手法07:Remove Assignments to Parameters (移除对参数的赋值)

代码对一个 参数赋值.以一个临时变量取代该参数的位置.     int Discount(int inputVal, int quantity, int yearTodate) { if (inputVal > 50) { inputVal -= 2; } } 重构后: int Discount(int inputVal, int quantity, int yearTodate) { int result=inputVal; if (inputVal > 50) { result -= 2;

重构改善既有代码设计--重构手法04:Replace Temp with Query (以查询取代临时变量)

所谓的以查询取代临时变量:就是当你的程序以一个临时变量保存某一个表达式的运算效果.将这个表达式提炼到一个独立函数中.将这个临时变量的所有引用点替换为对新函数的调用.此后,新函数就可以被其他函数调用. 例子如下: double basePrice = _quantity*_itemPrice; if (basePrice > 1000) { return basePrice * 0.95; } else { return basePrice * 0.98; } 重构之后代码: if (BasePr

重构改善既有代码设计--重构手法16:Introduce Foreign Method (引入外加函数)&& 重构手法17:Introduce Local Extension (引入本地扩展)

重构手法16:Introduce Foreign Method (引入外加函数)你需要为提供服务的类增加一个函数,但你无法修改这个类.在客户类中建立一个函数,并以第一参数形式传入一个服务类实例. 动机:这种事情发生了太多次了,你正在使用一个类,它真的很好,为你提供了需要的所有服务.而后,你又需要一项新服务,这个类却无法供应.于是你开始咒骂“为什么不能做这件事?”如果可以修改源码,你便可以自行添加一个新函数:如果不能,你就得在客户端编码,补足你要的那个函数. 如果客户类只使用这项功能一次,那么额外

重构改善既有代码设计--重构手法 之重新组织你的函数总结

前面讲了那么多的重构手法,估计学完后都会忘记,因此暂停下脚本,总结下,其实前面的所有重构手段,围绕一个主题:函数.即对函数的优化:为此首先一个函数里面代码很长,那么此时我们要做的就是提炼函数. 提炼函数的过程中,我们会产生新的函数,这个时候最重要的就是,是否有变量的引用,如果没有,那么这个函数很好提炼:如果有,那么就看是否会在子函数或者说新拆的函数中会对其赋值操作,如果没有赋值操作,那么也很简单,那么就直接将这个变量以参数的形式传入进去.那么最麻烦的就是,在拆出来的函数中会引用到原函数中的变量:

重构改善既有代码设计--重构手法08:Replace Method with Method Object (以函数对象取代函数)

你有一个大型函数,其中对局部变量的使用,使你无法釆用 Extract Method. 将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的值域(field) 然后你可以在同一个对象中将这个大型函数分解为数个小型函数. class Order... double price() { double primaryBasePrice; double secondaryBasePrice; double tertiaryBasePrice; // long computation; ... }

重构改善既有代码设计--重构手法02:Inline Method (内联函数)& 03: Inline Temp(内联临时变量)

Inline Method (内联函数) 一个函数调用的本体与名称同样清楚易懂.在函数调用点插入函数体,然后移除该函数. int GetRating() { return MoreThanfiveLateDeliverise() ? 2 : 1; } bool MoreThanfiveLateDeliverise() { return _numberOfLateLiveries > 5; } int GetRating() { return _numberOfLateLiveries > 5

重构改善既有代码设计--重构手法01:Extract Method (提炼函数)

背景: 你有一段代码可以被组织在一起并独立出来.将这段代码放进一个独立函数,并让函数名称解释该函数的用途. void PrintOwing(double amount) { PrintBanner(); //print details Console.WriteLine("name:"+_name); Console.WriteLine("amount:"+_amount); } void PrintOwing(double amount) { PrintBanne

重构改善既有代码设计--重构手法19:Replace Data Value with Object (以对象取代数据值)

你有一笔数据项(data item),需要额外的数据和行为. 将这笔数据项变成一个对象. class Order... private string customer; ==> class Order... private Customer _customer; class Customer... private string _name; 动机 一开始你可能会用一个字符串来表示[电话号码]概念,但是随后你就会发现,电话号码需要[格式化].[抽取区号]之类的特殊行为.当这些臭味开始出现,你就应该