重构——重新组织函数 - 新闻资讯 - 云南小程序开发|云南软件开发|云南网站建设-昆明葵宇信息科技有限公司

159-8711-8523

云南网建设/小程序开发/软件开发

知识

不管是网站,软件还是小程序,都要直接或间接能为您产生价值,我们在追求其视觉表现的同时,更侧重于功能的便捷,营销的便利,运营的高效,让网站成为营销工具,让软件能切实提升企业内部管理水平和效率。优秀的程序为后期升级提供便捷的支持!

您当前位置>首页 » 新闻资讯 » 技术分享 >

重构——重新组织函数

发表时间:2020-10-19

发布人:葵宇科技

浏览次数:31

Extract Method提炼函数

动机

首先如果每个函数的粒度都很小,那么函数被复用的机会就更大;其次,这会使高层函数读起来就像一系列注释;再次,如果函数都是细粒度,那么函数的覆写也会更容易。

做法

  • 创造一个新函数,根据这个函数的意图来对它进行命名(以它“做什么”来命名而是“怎么做”)。

  • 将提炼出来的代码从源函数复制到新建的目标函数中。

  • 仔细检查提炼出的代码,看看其中是否引用了作用域限于源函数的变量(包括局部变量和源函数参数);

  • 检查是否有“仅用于被提炼代码段”的临时变量,如果有,在目标函数中将它们声明为临时变量。

  • 检查被提炼代码段,看看是否有任何局部变量的值被它改变,如果有一个临时变量值被修改了,看看是否可以将提炼代码段处理为一个查询,并将结果赋值给相关变量。

  • 将被提炼代码段中需要读取的局部变量当做参数传给目标函数。

  • 处理完所有局部变量后,进行编译。

Inline Method(内联函数)

在这里插入图片描述

动机

  • 简短的函数表现动作意图会使代码更清晰易读,但有时候会遇到某些函数,其内部代码和函数名称同样清晰易读;
  • 将一群不甚合理的函数内联到一个大型函数中,再从中提炼出组织合理的小型函数,比起既要移动一个函数、又要移动它所调用的其他所有函数,将整个大型函数作为曾提移动会比较简单;
  • 如果别人使用了套太多间接层,使得系统中的所有函数都似乎只是对另一个函数的简单委托,造成代码阅读时候在这些委托动作之间晕头转向,通常使用内联函数,当前指的是那些无用的间接层。

做法

  1. 检查函数,确定它不具有多态性;

  2. 找出这个函数的所有被调用点;

Inline Temp(内联临时变量)

在这里插入图片描述

动机

内联临时变量多半是作为以查询替代临时变量的一部分使用的,所以真正的动机出现在后者那,但是,如果你发现某个临时变量被赋予某个函数调用的返回值,虽然这并没有任何危害,但是如果妨碍了其他重构手法,就应该将它内联化。

做法

  1. 检查给临时变量赋值的语句,确保等号右边的表达式没有副作用;

  2. 如果这个临时变量并未被声明为final,则声明;

  3. 找到该临时变量的所有引用点,将它们替换为为临时变量赋值的表达式;

  4. 每次修改后,编译并测试;

  5. 修改完所有引用点之后,删除该临时变量的声明和赋值语句;

Replace Temp with Query(以查询取代临时变量)

在这里插入图片描述

动机

临时变量的问题在于:它们是暂时的,而且只能在所属函数内使用,由于临时变量只在所属函数内可见,所以它们会驱使你写出更长的函数,因为这样才能访问到函数上面定义的临时变量。如果把临时变量替换为一个查询,那么同一个类中的所有函数都将可以获得这份信息。局部变量会使代码难以被提炼,所以应尽可能把他们替换为查询式

这个重构手法比较简单的情况是:临时变量只被赋值一次,或者赋值给临时变量的表达式不受其他条件影响。对于其他情况可能需要先运用分解临时变量以查询函数和修改函数分离使得情况变得简单一些,如果你想替换的临时变量是用来收集结果的(例如循环中的累加值),就需要将这些程序逻辑复制到查询函数去。

做法

简单情况:

  1. 找出制备复制一次的临时变量,如果某个临时变量被赋值超过一次,考虑使用分离临时变量法将它分割成多个变量;

  2. 将该临时变量声明为final;

  3. 对该临时变量赋值之语句的等号右侧部分提炼到一个独立函数中;

对临时变量进行累加的循环可以被提炼为一个独立的函数,对于一个循环累加好几个值的时候,你应该针对每个累加值重复一遍,这样可以将所有临时变量替换为查询。

Introduce Explaining Variable(引入解释性变量)

在这里插入图片描述

动机

你可以用这项重构将每个条件子句提炼出来,以一个良好命名的临时变量来解释对应条件子句的意义。

Split Temporary Variable(分解临时变量)

在这里插入图片描述

动机

临时变量有各种不同的用途,其中某些用途会很自然地导致临时变量被多次赋值,循环变量结果收集变量就是典型的例子,除此之外,还有很多临时变量用于保存一段冗长代码的运算结果,以便稍后使用。这种临时变量应该只被赋值一次,如果它们被赋值多次,就意味着它们在函数中承担一个以上的责任,如果临时变量承担多个责任,它就应该被替换为多个临时变量,每个变量只承担一个责任。

做法

  1. 在待分解临时变量的声明及其第一次被赋值处修改其名称,除了累加、字符串结合、写入流或者向集合添加元素的变量。

  2. 将新的临时变量声明为final;

  3. 以该临时变量的第二次赋值动作为界,修改此前对该临时变量的所有引用点,让它们引用新的临时变量。

  4. 在第二次赋值处,重新声明原先那个临时变量;

  5. 逐次重复上述过程;

Remove Assignments to Parameters(移除对参数的赋值)

在这里插入图片描述

动机

不要对参数赋值,因为它降低了代码的清晰度,而且混用了按值传递和按引用传递这两种参数传递方式,Java只采用按值传递的方式。

在按值传递的情况下,对参数的任何修改都不会对调用端造成任何影响

做法

  1. 建立一个临时变量,把待处理的参数值赋予它;
  2. 对参数的赋值为界,将其后所有对此参数的引用点,全部替换为对此临时变量的引用
  3. 修改赋值语句,使其改为对新建临时变量赋值;

Replace Method with Method Object(以函数对象取代函数)

动机

将相对独立的代码从大型函数中提炼出来就可以大大提高代码的可读性,但是局部变量的存在会增加函数分解难度。

以函数对象取代函数会将所有局部变量都变成函数对象的字段,然后就可以对这个新对象使用提炼函数创造新函数,从而将原本的大型函数拆解变短。

做法

  1. 建立一个新类,根据待处理函数的用途,为这个类命名;
  2. 在新类中建立一个final字段,用以保存原先大型函数所在的对象,将这个字段称为源对象,同时,针对这个原函数的每个临时变量和每个参数在新类中建立一个对应的字段保存。
  3. 在新类中建立一个构造函数,接收源对象及原函数的所有参数作为参数;
  4. 在新类中建立一个compute()函数;
  5. 将原函数的代码复制到compute()函数中,如果需要调用源对象的任何函数,请通过源对象字段调用;
  6. 将就函数的函数本体替换为创建上述新类的一个新对象,而后调用其中的compute()函数

Substitile Algorithm(替换算法)

在这里插入图片描述

相关案例查看更多