你有一个大型函数,其中对局部变量的使用使你无法采用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. LinQ各种方式查询、组合查询、IQueryable集合类型

    1.模糊查询(包含) Repeater1.DataSource = con.car.Where(r =>r.name.Contains(s)).ToList(); 2.开头查询 Repeater ...

  2. Poj1258 Agri-Net (最小生成树 Prim算法 模板题)

    题目链接:http://poj.org/problem?id=1258 Description Farmer John has been elected mayor of his town! One ...

  3. sliver

    import 'package:flutter/material.dart';import 'package:xxx/bloc/bloc.dart';import 'package:xxx/model ...

  4. 基于Docker搭建MySQL多源复制环境

    MySQL5.7在主从复制上面相对之前版本多了一些新特性,包括多源复制.基于组提交的并行复制.在线修改Replication Filter.GTID增强.半同步复制增强等. 多源复制:多源复制加入了一 ...

  5. docker性能测试

    测试环境: 操作系统:CentOS7.openstack nova-docker启动的centos7.openstack环境启动的centos7虚拟机 CPU:Intel(R) Xeon(R) CPU ...

  6. Idea 全局替换指定字符

    最近使用idea开发,刚接触不久,然后碰到需要全局替换的时候,懵逼了.之前使用eclipse 直接Ctrl+F 就可以操作了. 现在使用idea 摁Ctrl+F竟然只能搜,不能替换....尴尬的一匹. ...

  7. i.MX6UL -- PWM用户空间使用方法【转】

    本文转载自:https://blog.csdn.net/u014486599/article/details/53010114 i.MX6UL -- PWM用户空间使用方法 开发平台: 珠海鼎芯D51 ...

  8. 【BZOJ4031】小Z的房间

    Description 你突然有了一个大房子,房子里面有一些房间.事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子.在一开始的时候,相邻的格子之间都有墙隔着. ...

  9. JS对象、数据类型区别、函数

    对象 基本数据类型都是单一的值,值和值之间没有任何联系,变量之间独立,不能成为一个整体. 对象属于一种符合的数据类型,对象中可以保存对个不同数据类型的属性. 对象分类:  1.内建对象   由ES标准 ...

  10. 《温故而知新》JAVA基础二

    基本条件语句 switch语句,case匹配后会执行匹配的代码,如果没有break语句,会继续执行后面的语句,直到遇到break和程序结束为止 2.while循环 1. whie(){ do some ...