重构 改善既有代码的设计 Replace Method with Method Object(以函数对象取代函数)
你有一个大型函数,其中对局部变量的使用使你无法采用Extract Method。
将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的字段。然后你可以在同一个对象中将这个大型函数分解为多个小型函数。
动机
我们一直在强调,小型函数优美动人。只要将相对独立的代码从大型函数中提炼出来,就大大提高了函数的可读性。
但是,局部变量的存在会增加函数分解难度。如果一个函数中局部变量泛滥成灾,那么这个时候Replace Temp with Query可以帮助你。有时候根本无法拆解一个需要拆解的函数,这时候Replace Method with Method Object就发挥作用了。
Replace Method with Method Object会将所有局部变量都变成函数对象的字段。然后就可以对这个新函数使用Extract Method创造新函数,从而达到拆解的目的。
范例
如果要找到合适的例子,那么需要很长的篇幅,所以我们杜撰了这样一个函数。

class Account
{
int Gamma(int inputVal, int quantity, int yearToDate)
{
int importantValue1 = inputVal * quantity + Delta();
int importantValue2 = inputVal * yearToDate + 100;
if (yearToDate - importantValue1 > 100)
{
importantValue2 -= 20;
}
int importantValue3 = importantValue2 * 7;
//and so on...
return importantValue3 - 2 * importantValue1;
}
public int Delta()
{
return 100;
}
}

为了把这个函数变成函数对象,首先声明一个新类。在新类中,提供一个字段用于保存原对象,同时也对函数的每个参数和每个临时变量,提供字段用于保存。

class Gamma
{ private readonly Account _account; private readonly int _inputVal; private readonly int _quantity; private readonly int _yearToDate; private int _importantValue1; private int _importantValue2; private int _importantValue3;
}

接下来,加入一个构造函数:

public Gamma(Account account, int inputVal, int quantity, int yearToDate)
{
_account = account;
_inputVal = inputVal;
_quantity = quantity;
_yearToDate = yearToDate;
}

接下来,将原本的函数搬到Compute()中。

public int Compute()
{
_importantValue1 = _inputVal * _quantity + _account.Delta();
_importantValue2 = _inputVal * _yearToDate + 100;
if (_yearToDate - _importantValue1 > 100)
{
_importantValue2 -= 20;
}
_importantValue3 = _importantValue2 * 7;
//and so on...
return _importantValue3 - 2 * _importantValue1;
}

完整的Gamma函数如下:

class Gamma
{ private readonly Account _account; private readonly int _inputVal; private readonly int _quantity; private readonly int _yearToDate; private int _importantValue1; private int _importantValue2; private int _importantValue3;
public Gamma(Account account, int inputVal, int quantity, int yearToDate)
{
_account = account;
_inputVal = inputVal;
_quantity = quantity;
_yearToDate = yearToDate;
}
public int Compute()
{
_importantValue1 = _inputVal * _quantity + _account.Delta();
_importantValue2 = _inputVal * _yearToDate + 100;
if (_yearToDate - _importantValue1 > 100)
{
_importantValue2 -= 20;
}
_importantValue3 = _importantValue2 * 7;
//and so on...
return _importantValue3 - 2 * _importantValue1;
}
}

最后,修改旧函数,让它的工作委托给刚完成的这个函数对象。
int Gamma(int inputVal, int quantity, int yearToDate)
{
return new Gamma(this, inputVal, quantity, yearToDate).Compute();
}
这就是本项重构的基本原则。它的好处是:现在我们可以轻松地对Compute()函数采取Extract Method,不必担心参数传递的问题。
比如说我们对Compute进行如下重构:

public int Compute()
{
_importantValue1 = _inputVal * _quantity + _account.Delta();
_importantValue2 = _inputVal * _yearToDate + 100;
GetImportantThing();
_importantValue3 = _importantValue2 * 7;
//and so on...
return _importantValue3 - 2 * _importantValue1;
} void GetImportantThing()
{
if (_yearToDate - _importantValue1 > 100)
{
_importantValue2 -= 20;
}
}

重构 改善既有代码的设计 Replace Method with Method Object(以函数对象取代函数)的更多相关文章
- 【转】PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数
原文地址: PHP 杂谈<重构-改善既有代码的设计>之一 重新组织你的函数 思维导图 点击下图,可以看大图. 介绍 我把我比较喜欢的和比较关注的地方写下来和大家分享.上次我写 ...
- 《重构——改善既有代码的设计》【PDF】下载
<重构--改善既有代码的设计>[PDF]下载链接: https://u253469.ctfile.com/fs/253469-231196358 编辑推荐 重构,一言以蔽之,就是在不改变外 ...
- 《重构--改善既有代码的设计》总结or读后感:重构是程序员的本能
此文写得有点晚,记得去年7月读完的这本书,只是那时没有写文章的意识,也无所谓总结了,现在稍微聊一下吧. 想起写这篇感想,还是前几天看了这么一篇文章 研究发现重构软件并不会改善代码质量 先从一个大家都有 ...
- 重构 改善既有代码的设计 (Martin Fowler 著)
第1章 重构, 第一个案例 1.1 起点 1.2 重构的第一步 1.3 分解并重组 statement() 1.4 运用多态取代与价格相关的条件逻辑 1.5 结语 第2章 重构原则 2.1 何谓重构 ...
- 『重构--改善既有代码的设计』读书笔记----Replace Method with Method Object
有时候,当你遇到一个大型函数,里面的临时变量和参数多的让你觉得根本无法进行Extract Method.重构中也大力的推荐短小函数的好处,它所带来的解释性,复用性让你收益无穷.但如果你遇到上种情况,你 ...
- 重构改善既有代码设计--重构手法08:Replace Method with Method Object (以函数对象取代函数)
你有一个大型函数,其中对局部变量的使用,使你无法釆用 Extract Method. 将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的值域(field) 然后你可以在同一个对象中将这个大型 ...
- 『重构--改善既有代码的设计』读书笔记----Replace Temp with Query
Replace Temp with Query,顾名思义,表示你用查询来替换临时变量本身,临时变量对于函数来说是只有当前函数可见的,如果你在同类的别的地方要用到这个变量你就必须重新写表达式来获取这个变 ...
- 『重构--改善既有代码的设计』读书笔记----Change Value to Reference
有时候你会认为某个对象应该是去全局唯一的,这就是引用(Reference)的概念.它代表当你在某个地点对他进行修改之后,那么所有共享他的对象都应该在再次访问他的时候得到相应的修改.而不会像值对象(Va ...
- 『重构--改善既有代码的设计』读书笔记----Extract Method
在编程中,比较忌讳的一件事情就是长函数.因为长函数代表了你这段代码不能很好的复用以及内部可能出现很多别的地方的重复代码,而且这段长函数内部的处理逻辑你也不能很好的看清楚.因此,今天重构第一个手法就是处 ...
随机推荐
- LinQ各种方式查询、组合查询、IQueryable集合类型
1.模糊查询(包含) Repeater1.DataSource = con.car.Where(r =>r.name.Contains(s)).ToList(); 2.开头查询 Repeater ...
- myBatis学习之路1-基本功能实现
myBatis也是一个持久型框架,相较于hibernate来说,算是轻量级的. 1.配置mybatis环境 相关jar下载地址:mybatis+mysalJAR包 2.新建一个java project ...
- Docker Swarm 配置文件存储
Docker Swarm 配置文件存储 config:宿主级容器服务配置文件单独保存到docker中存储调用. 环境: 系统:Centos 7.4 x64 应用版本:Docker 18.09.0 管理 ...
- Python sqlalchemy orm 外键关联
创建外键关联 并通过relationship 互相调用 如图: 实现代码: import sqlalchemy # 调用链接数据库 from sqlalchemy import create_engi ...
- ps | grep排除grep这个进程
我们经常用ps | grep xxx来查询是否存在某进程,但默认情况下会将grep这个命令也作为结果返回,这样无论是否存在查询的进程,该命令的返回值都是0. 要避免这种情况可以使用grep的-v参数, ...
- 2. Dubbo原理解析-Dubbo内核实现之基于SPI思想Dubbo内核实现(转)
转载自 斩秋的专栏 http://blog.csdn.net/quhongwei_zhanqiu/article/details/41577159 SPI接口定义 定义了@SPI注解 public ...
- 【jvisualvm远程监控配置】
第一步:首先通过hostname -i 和ifconfig命令,查看一下IP地址是否一致 如果不一致,修改hosts的IP地址:vi /etc/hosts 把ip地址和ifconfig的地址修 ...
- maven 执行testng.xml文件失败解决问题
在pom.xml中配置了testng的依赖后,在surefire-plugin中又配置了suitexmlfiles指向testng.xml文件,但是使用mvn test运行时,没有运行testng.x ...
- 委托&&异步
private void ShowMessage(string message) { this.BeginInvoke(new MethodInvoker(delegate { txtSysMessa ...
- 【做题】agc006e - Rotate 3x3——分析&思维
原文链接 https://www.cnblogs.com/cly-none/p/9800105.html 题意:给出一个三行\(n\)列的矩阵.问它能否由满足\(a_{ij} = 3(j-1) + i ...