你有一个大型函数,其中对局部变量的使用使你无法采用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(以函数对象取代函数)的更多相关文章

  1. 【转】PHP 杂谈《重构-改善既有代码的设计》之一 重新组织你的函数

    原文地址: PHP 杂谈<重构-改善既有代码的设计>之一 重新组织你的函数 思维导图   点击下图,可以看大图.    介绍   我把我比较喜欢的和比较关注的地方写下来和大家分享.上次我写 ...

  2. 《重构——改善既有代码的设计》【PDF】下载

    <重构--改善既有代码的设计>[PDF]下载链接: https://u253469.ctfile.com/fs/253469-231196358 编辑推荐 重构,一言以蔽之,就是在不改变外 ...

  3. 《重构--改善既有代码的设计》总结or读后感:重构是程序员的本能

    此文写得有点晚,记得去年7月读完的这本书,只是那时没有写文章的意识,也无所谓总结了,现在稍微聊一下吧. 想起写这篇感想,还是前几天看了这么一篇文章 研究发现重构软件并不会改善代码质量 先从一个大家都有 ...

  4. 重构 改善既有代码的设计 (Martin Fowler 著)

    第1章 重构, 第一个案例 1.1 起点 1.2 重构的第一步 1.3 分解并重组 statement() 1.4 运用多态取代与价格相关的条件逻辑 1.5 结语 第2章 重构原则 2.1 何谓重构 ...

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

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

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

    你有一个大型函数,其中对局部变量的使用,使你无法釆用 Extract Method. 将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的值域(field) 然后你可以在同一个对象中将这个大型 ...

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

    Replace Temp with Query,顾名思义,表示你用查询来替换临时变量本身,临时变量对于函数来说是只有当前函数可见的,如果你在同类的别的地方要用到这个变量你就必须重新写表达式来获取这个变 ...

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

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

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

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

随机推荐

  1. Divide the Sequence (贪心)

    题意:求将一串数据尽可能多分成所有前缀和大于0的连续子串. 思路:由于是要求所有前缀和大于0,那么只要从后往前推就好了. #include<bits/stdc++.h> using nam ...

  2. Linux分区、文件系统

    Linux分区类型: ◆主分区:总共最多只能分四个 ◆扩展分区:只能有一个,也算作主分区的一种,也就是 说主分区不能存储数据和格式化,必须再划分为逻辑分区才能使用. ◆逻辑分区:逻辑分区是在扩展分区中 ...

  3. ACM总结——2017ACM-ICPC北京赛区现场赛总结

    现在距离比赛结束已经过了一个多星期了,也是终于有时间写下心得了.回来就是被压着做项目,也是够够的. 这次比赛一样是我和两个学弟(虽然是学弟,但我的实力才是最弱的T_T)一起参加的,成绩的话打铁,算是情 ...

  4. Java 泛型方法、泛型类、通配符、通配符上下限

    泛型方法 泛型方法定义规则: 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前. 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开.一个泛型 ...

  5. git的一些补充点

    git rm和 rm的区别 git rm是删除文件, 同时加入到git的跟踪管理中,做一个登记,那么在git commit的时候, 会把这次删除作为一次修改提交上去, 否则, 在 git log中你就 ...

  6. codeforce gym/100495/problem/K—Wolf and sheep 两圆求相交面积 与 gym/100495/problem/E—Simple sequence思路简述

    之前几乎没写过什么这种几何的计算题.在众多大佬的博客下终于记起来了当时的公式.嘚赶快补计算几何和概率论的坑了... 这题的要求,在对两圆相交的板子略做修改后,很容易实现.这里直接给出代码.重点的部分有 ...

  7. vue实现 toggle显示隐藏效果

    背景介绍jQuery中有个toggle()方法,可以切换元素的显示状态,在用vue时如果不引入jQuery如何实现这种效果?使用场景常见有三种场景:1.控制页面中一个dom元素2.控制页面中多个dom ...

  8. 【JS面试向】选择排序、桶排序、冒泡排序和快速排序简介

    新年伊始,又到了金三银四的时候了.面对前端越来越多的算法面试题,我简单的整理了一下几种比较常见的数组排序方式,分别介绍其基本原理和优劣势.(ps:才疏学浅,希望大家可以在issues下面指出问题) 选 ...

  9. 补充一下 sizeof

    sizeof是一个运算符,给出某个类型或变量在内存中所占据的字节数 sizeof(int) //告诉你int占据几个字节 sizeof(i) //告诉你i这个变量占据几个字节 注:sizeof是静态运 ...

  10. E: Unable to locate package git

    git can’t install 报错信息: root@281eef85bb5d:~# apt-get install git Reading package lists... Done Build ...