当你无法获得一个类的源代码或者没有权限去修改这个类的时候,你对于这种为你服务的类,你可能会出现需要别的需求的时候,比如一个Date类,你需要能够让他本身直接返回出他的后一天的对象,但他没有,这个时候你就需要暂时使用Introduce Foreign Method来做过渡,并且在适当时候通知作者把这个Foreign Method搬移到他所属于的自己的类中去。

这种情况其实也很多,特别是当你在团队当中,当有别人写了一个类的时候,你会去利用这个类去做你想要做的事情,但如果你发现这个类并没有提供你所要的功能,如果你可以去修改源代码,那当然可以。你可以直接在类的源代码中增加一行你所想要的功能。但如果你不能获取源代码,你就只能在客户端编码,补充你所想要的那个函数。

当然,如果你所处的客户类只使用这项功能一次,那没什么大不了,你可以完全额外添加多出来的处理逻辑。甚至你可能都不需要原来提供服务的那个对象本身,但是,如果你需要多次去使用这个函数,你就不得不去重复这些代码,还记得吗

重复代码是软件的万恶之源。

这些重复代码应该被抽出来运用Extract Method放进同一个函数中去,当然如果你迫不得已执行本次重构,这也给了你一个明确的信号:这个函数原本应该在提供服务的类中实现。

如果你发现自己已经为一个服务类增加的大量函数,或者发现有许多类都需要同样的外加函数,你就不应该再使用本次重构,而应该使用Introduce Local Extension。但是请不要忘记,Foreign Method始终是权宜之计,如果有可能,你仍然应该将这些函数通过Move Method搬移到他们的理想家园。如果你无法进行这样的搬移,你也可以把这个外加函数交给服务类的拥有者,请他帮你在服务类中实现这个函数。

做法:

  • 在客户类中建立一个函数,用来提供你需要的功能。这个函数不应该调用客户类的任何特性,如果他需要一个值,把值当作传输传给他,而不是让他在函数内部本身去调用你客户类的特性。在这里有一个技巧,为了避免之前说的那种可能会让你提炼的函数引用客户类的特性,我们可以在新创建的函数给他static特性,大家都知道C++的static会迫使你不能去接触所属类的特性。
  • 以服务类实例作为这个函数的第一个参数。
  • 将该函数注释为“foreign method应该在服务类中实现”来提醒你将来有机会将外加函数搬移道服务类中的时候可以很快速的找到这些函数。

例子:

  1. Date newStart = new Date(perviousEnd.getYear(), perviousEnd.getMonth(), perviousEnd.getDate()
  2. + );

在例子中我们可以看到,我在客户端代码里需要一个跨越一个收费周期的函数,但实际Date并不提供这个函数,所以我只能自己写一个冗长的new。当然,如果出现一处这种地方我们不需要太在意,但是如果出现多出,我们就需要使用Extract Method进行重构,这个函数就是Date类的外加函数。我们可以这么声明

  1. Date newStart = nextDay(perviousEnd);
  2.  
  3. static Date nextDay(Date arg)
  4. {
  5. // foreign method, should be on Date
  6. return new Date(arg.getYear(), arg.getMonth(), arg.getDate()
  7. + );
  8. }

可以看到,我们让这个函数变成static这样可以保证我们不使用客户端类的任何特性,同时我们把这个函数的第一个参数作为服务类对象传进,这样我们以后在进行Move Method的时候可以得到无参化的简洁接口。

『重构--改善既有代码的设计』读书笔记----Introduce Foreign Method的更多相关文章

  1. 『重构--改善既有代码的设计』读书笔记----Introduce Local Extension

    同Introduce Foreign Method一样,很多时候你不能修改编辑原始类,你需要为这些服务类增加一些额外的函数,但你没有这个权限或者入口.如果你只需要一个或者两个外加函数那么你可以放心的使 ...

  2. 『重构--改善既有代码的设计』读书笔记----Introduce Explaning Variable

    有时候你会遇到一系列复杂的表达式连续运算的时候,这个时候你可能根本招架不住如此长或者是如此复杂的长函数.这个时候你可以通过引用临时变量来储存他们的结果,将这些长函数的结果分成一个个临时变量来让函数清晰 ...

  3. 『重构--改善既有代码的设计』读书笔记----Extract Method

    在编程中,比较忌讳的一件事情就是长函数.因为长函数代表了你这段代码不能很好的复用以及内部可能出现很多别的地方的重复代码,而且这段长函数内部的处理逻辑你也不能很好的看清楚.因此,今天重构第一个手法就是处 ...

  4. 『重构--改善既有代码的设计』读书笔记----Change Value to Reference

    有时候你会认为某个对象应该是去全局唯一的,这就是引用(Reference)的概念.它代表当你在某个地点对他进行修改之后,那么所有共享他的对象都应该在再次访问他的时候得到相应的修改.而不会像值对象(Va ...

  5. 『重构--改善既有代码的设计』读书笔记----Replace Method with Method Object

    有时候,当你遇到一个大型函数,里面的临时变量和参数多的让你觉得根本无法进行Extract Method.重构中也大力的推荐短小函数的好处,它所带来的解释性,复用性让你收益无穷.但如果你遇到上种情况,你 ...

  6. 『重构--改善既有代码的设计』读书笔记---Duplicate Observed Data

    当MVC出现的时候,极大的推动了Model与View分离的潮流.然而对于一些已存在的老系统或者没有维护好的系统,你都会看到当前存在大把的巨大类----将Model,View,Controller都写在 ...

  7. 『重构--改善既有代码的设计』读书笔记----Replace Array with Object

    如果你有一个数组,其中的元素各自代表不同东西,比如你有一个 QList<QString> strList; 其中strList[0]代表选手姓名,strList[1]代表选手家庭住址,很显 ...

  8. 『重构--改善既有代码的设计』读书笔记----Self Encapsulate Field

    如果你直接访问一个字段,你就会和这个字段直接的耦合关系变得笨拙.也就是说当这个字段权限更改,或者名称更改之后你的客户端代码都需要做相应的改变,此时你可以为这个字段建立设值和取值函数并且只以这些函数来访 ...

  9. 『重构--改善既有代码的设计』读书笔记----Move Method

    明确函数所在类的位置是很重要的.这样可以避免你的类与别的类有太多耦合.也会让你的类的内聚性变得更加牢固,让你的整个系统变得更加整洁.简单来说,如果在你的程序中,某个类的函数在使用的过程中,更多的是在和 ...

随机推荐

  1. centos下apache thrift的安装

    参考:http://running.iteye.com/blog/1983463  thrift-0.9.0安装 最好切换到root用户操作,避免不必要的麻烦. 进行例子程序tutorial目录下,通 ...

  2. JDK6 下载地址

    http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-javase6-41940 ...

  3. Android关于ListView中item与控件抢夺焦点的那些事

    在开发中,listview可以说是我们使用最频繁的控件之一了,但是关于listview的各种问题也是很多.当我们使用自定义布局的Listview的时候,如果在item的布局文件里面存在Button或者 ...

  4. [Reactive Programming] Using an event stream of double clicks -- buffer()

    See a practical example of reactive programming in JavaScript and the DOM. Learn how to detect doubl ...

  5. android 36 线程通信

    安卓中一个程序跑起来叫进程,进程中至少有一个主线程.主线程用于处理用户的触摸操作和将触摸操作事件分发给响应的控件.如果进行消耗时间操作,下载,磁盘读取文件,不润许在主线程操作,只能在工作线程操作.主线 ...

  6. hdu2660 Accepted Necklace (DFS)

    Problem Description I have N precious stones, and plan to use K of them to make a necklace for my mo ...

  7. [转] Python特殊语法:filter、map、reduce、lambda

    Python内置了一些非常有趣但非常有用的函数,充分体现了Python的语言魅力! filter(function, sequence):对sequence中的item依次执行function(ite ...

  8. oracle多表关联删除数据表记录方法

    oracle多表关联删除的两种方法 第一种使用exists方法 delete from tableA where exits ( select 1 from tableB Where tableA.i ...

  9. java io 流基础

  10. 第一篇:python基础

    python基础   python基础 本节内容 python起源 python的发展史 为什么选择python3 第一个python程序 变量定义 表达式和运算符 用户输入 流程控制 判断 流程控制 ...