search
HomeDatabaseMysql Tutorial重构(Refactoring)技巧 读书笔记

本文简要整理重构方法的读书笔记及个人在做Code Review过程中,对程序代码常用的一些重构策略。通过适当的重构代码,的确可以显著提高代码的质量,令人赏心悦目。毫无疑问,这些重构策略均来自于Martin Fowler的《重构-改善既有代码的设计》,只是如何在实

本文简要整理重构方法的读书笔记及个人在做Code Review过程中,对程序代码常用的一些重构策略。通过适当的重构代码,的确可以显著提高代码的质量,令人赏心悦目。毫无疑问,这些重构策略均来自于Martin Fowler的《重构-改善既有代码的设计》,只是如何在实际项目中灵活运用而已。(注:本文重构策略的名称及其大部分内容来自《重构-改善既有代码的设计》一书,Martin Fowler 著,侯捷等译)。

先看看重构的定义吧:

(1)Refactoring means rewriting existing source code with the intent of improving its design rather than changing its external behavior. The focus of refactoring is on the structure of the source code, changing the design to make the code easier to understand, maintain, and modify. - 来自Borland Together提供的文档,觉得这个定义很清晰明了。

(2)重构是这样一个过程:在不改变代码外在行为的前提下,对代码做出修改,已改进程序的内部结构。-来自Martin Fowler的定义。

不过,我一般使用一些重构的工具,如ReSharper for VS.Net v1.0和Borland Together for VS.Net v2.0,这些重构工具可以帮助你做很多事情,可以简化你许多工作,同时也可以避免出现一些错误。关于ReSharper for VS.Net v1.0的简单介绍,可以参考本人以前的一篇Posting【体验ReSharper V1.0 for VS.Net 2003 - Part I体验ReSharper V1.0 for VS.Net 2003 - Part II】。另外VS.Net 2005已经内置了重构功能。不过,目前这些重构工具还远远不能涵盖各种重构方法,有总比没有好了。

因此,掌握必要的重构技巧逐步成为对程序员基本的要求,重要的是在掌握这些技巧后,也有助于类库初期设计的质量,避免或减少代码的坏味道(bad smell)。

 

一、代码坏味道(Bad Smell in Codes)及其重构策略

1.尽量消除重复的代码,将它们合而为一

根据重复的代码出现在不同的地方,分别采取不同的重构的策略:

在同一个Class的不同地方:通过采用重构工具提供的Extract Method功能提炼出重复的代码, 然后在这些地方调用上述提炼出方法。

在不同Subclasses中:通过Extract Method提炼出重复的代码,然后通过Pull Up Method将该方法移动到上级的Super class内。

在没有关系的Classes中:通过对其中一个使用Extract Class将重复的代码提炼到一个新类中,然后在另一个Class中调用生成的新类,消除重复的代码。

 

2.拆解过长的函数

过长的函数在我们的日常代码中经常可见,在C#中常通过#region #endregion区隔为不同的功能区域。

重构策略:通过Extract Method将过长的函数按照功能的不同进行适当拆解为小的函数,并且给这些小函数一个好名字。通过名字来了解函数提供的功能,提高代码的理解性。

 

3.拆解过大的类

过大的类也经常见到,特别是类中含有大量的成员变量。

重构策略:通过Extract Class将一些相关成员变量移植到新的Class中,如Employee类,一般会包含有联系方式的相关属性(电话, Mobile,地址,Zip等等),则可以将这些移植到新的EmployeeContact类中。

 

4.过长的参数列

过长的参数列的主要问题是难以理解,并且难以维护。如果要增加新的参数或者删除某一参数,易造成参数前后不一致。

重构策略:如果可以通过向已存在的对象查询获取参数,则可通过Replace Parameter with Method,移除参数列,通过在函数内部向上述已存在的对象查询来获取参数。

如果参数列中若干参数是已存在对象的属性,则可通过Preserve Whole Object将这些参赛替换为一个完整对象,这样不仅提高代码的可读性,同时已易于代码今后的维护。

另外,还可以将若干不相关的参数,使用Introduce Parameter Object来创建一个新的参数类。不过,我个人觉得如果这些情况过多的话,会产生很多莫名其妙的参数类了,反而降低代码的可读性。

 

个人觉得前面4种坏味道比较显而易见,也比较容易处理。


本文继续《重构(Refactoring)技巧读书笔记 之一》,重构的确是未来软件工程师需要掌握的一项技能。目前一些支持.Net的重构工具,如ReSharper for VS.Net v1.0、Borland Together for VS.Net v2.0和VS.Net 2005等,只能支持一些有限的、比较简单的重构策略。大量的重构策略需要软件工程师清晰的了解,人工为主,运用重构工具辅助进行。(注:本文重构策略的名称及其大部分内容来自《重构-改善既有代码的设计》一书,Martin Fowler 著,侯捷等译)。

下面的内容延续上一节的内容,其中提及的一些代码坏味道(Bad Smell in Codes)及其重构策略相对而言要比较麻烦一些。

 

一、代码坏味道(Bad Smell in Codes)及其重构策略

5Divergent Change(发散式变化)

现象:当某个Class因为外部条件的变化或者客户提出新的功能要求等时,每次修改要求我们更新Class中不同的方法。不过这种情况只有在事后才能觉察到,因为修改都是在事后发生的么(废话)。

重构策略:将每次因同一条件变化,而需要同时修改的若干方法通过Extract Class将它们提炼到一个新Class中。实现目标是:每次变化需要修改的方法都在单一的Class中,并且这个新的Class内所有的方法都应该与这个变化相关。

 

6Shotgun Surgery(霰弹式修改)

现象:当外部条件发生变化时,每次需要修改多个Class来适应这些变化,影响到很多地方。就像霰弹一样,发散到多个地方。

重构策略:使用Move Method和Move Field将Class中需要修改的方法及成员变量移植到同一个Class中。如果没有合适的Class,则创建一个新Class。实现目标是,将需要修改的地方集中到一个Class中进行处理。

 

比较Divergent Change(发散式变化)和Shotgun Surgery(霰弹式修改):

前者指一个Class受到多种外部变化的影响。而后者指一种变化需要影响到多个Class需要修改。都是需要修理的对象。

 

7Feature Envy(依恋情结)

现象:Class中某些方法“身在曹营心在汉”,没有安心使用Class中的成员变量,而需要大量访问另外Class中的成员变量。这样就违反了对象技术的基本定义:将数据和操作行为(方法)包装在一起。

重构策略:使用Move Method将这些方法移动到对应的Class中,以化解其“相思之苦”,让其牵手。

 

8Data Clumps(数据泥团)

现象:指一些相同数据项目(Data Items),如Class成员变量和方法中参数列表等,在多个Class中多次出现,并且这些数据项目有其内在的联系。

重构策略:通过使用Introduce Parameter Object(创建新的参数对象取代这些参数)或Preserve Whole Object(使用已存在的对象取代这些参数),实现使用对象代替Class成员变量和方法中参数列表,清除数据泥团,使代码简洁,也提高维护性和易读性。

 

9Primitive Obsession(基本型偏执狂)

现象:在Class中看到大量的基本型数据项目(Data Item),如Employee类中有大量的数据成员,Employee#, FirstName, MiddleName, LastName, Address, State, City, Street, Zip, OfficePhone, CellPhone, Email……等等。

重构策略:使用Extract Class(提炼新类)或Preserve Whole Object(使用已存在的对象取代这些参数),实现使用对象代替基本型数据项目(Data Item)。如上述Employee类中就可分别提炼出EmployeeName和EmployeeContact两个新类。

 

10Switch StatementsSwitch语句)

现象:同样的Switch语句出现在不同的方法或不同的Class中,这样当需要增加新的CASE分支或者修改CASE分支内语句时,就必须找到所有的地方,然后进行修改。这样,就比较麻烦了。

重构策略:(1)首先采用Extract Method将Switch语句提炼到一个独立的函数。

(2)然后以Move Method搬移到需要多态性(Polymorphism)的Superclass里面或者是构建一个新的Superclass。

(3)进一步使用Replace Type Code with Subclasses或者Replace Type Code with State/Strategy。这步就比较麻烦些,不过记住如下基本规则:这里一般有3个Class分别为Source Class、Superclass和Subclass。

Source Class:

l         使用Self Encapsulate Field,将Type Code成员变量封装起来,也就是建立对应的Setter/Getter函数。

l         在Source Class中增加一个Superclass类型的成员变量,用来存放Subclass实例对象。

l         在Source Class中的Getter函数,通过调用Superclass的Abstract Query函数来完成。

l         在Source Class中的Setter函数,通过调用Superclass中的Static工厂化方法来获取合适的Subclass实例对象。

 

Superclass:

新建的一个Class(注:就是上面通过Move Method搬移生成的Superclass),根据Type Code的用途命名该Class,作为Superclass。

l         在Superclass中建立一个Abstract Query函数,用来获取Subclass的Type Code。

l         在Superclass中创建Static工厂化方法生产对应的Subclass对象,这里会存在一个Switch语句(不要再动脑筋来重构这个Switch语句了,这个Switch语句不会在多处重复存在,并且这里用于决定创建何种Subclass对象,这是完全可以接受的)。

 

Subclass:

l         根据每一个Switch/Type分支,建立对应的Subclass,并且Subclass的命名可以参考Switch/Type分支的命名。

l         在每一个Subclass中重载Superclass的Abstract Query函数,返回特定的Type Code。

(4)现在Superclass仍然存在Switch分支,是时候轮到Replace Conditional with Polymorphism上场了。具体而言,就是在每一个Subclass中创建重载方法(注:该方法是Superclass中含有Switch语句的方法),并将Superclass中Switch语句对应的Case分支剪切过来。最后将Superclass中该方法初象化Abstract,并清除Switch语句及其所有的Case分支。

这样就完成了整个重构过程,这个比较麻烦。

 

注:并不是一看到Switch语句及CASE分支,就马上/偏执狂采用上述重构策略进行重构,画蛇添足或吃亏不讨好(个人观点)。一般而言,只有看到多处出现相同的Switch语句时,才应该考虑进行重构。

 

动了情的至尊宝在那个月圆之夜有感而发:长夜漫漫,无心睡眠。从此,他的夜生活变得多姿多彩起来。唉,我以为只有至尊宝才有这等幸运。

想起放在抽屉的《重构》,遂拜读大师的作品来催眠,度过一个无心睡眠的漫漫长夜。

……

本文继续重构(Refactoring)技巧读书笔记系列。重构虽然是对现有的代码进行设计,以提高代码的质量和灵活性,但实际上,如果软件工程师掌握重构技术,对其初期的软件设计也有很好的指导,减少不当设计或设计不足,减少代码坏味道(Bad Smell in Codes),构建良好的系统。

注:本文重构策略的名称及其大部分内容来自《重构-改善既有代码的设计》一书,Martin Fowler 著,侯捷等译。

 

 

一、代码坏味道(Bad Smell in Codes)及其重构策略

11Parallel Inheritance Hierarchies(平行继承体系)

现象:为某个class增加一个subclass时,也必须为另一个class相应增加一个subclass。重构策略: 在一个class继承体系的对象中引用(refer to)另一个class继承体系的对象,然后运用Move Method和Move Field将被引用class中的一些方法和成员变量迁移宿主class中,消除被引用class的继承体系(注:这种平行继承体系好象比较少见也)。

 

12Lazy Class(冗赘类)

现象:某一些class由于种种原因,现在已经不再承担足够责任,有些多余了。如同国有企业冗余人员一样,需要下岗了。

重构策略:通过Collapse Hierarchy,将这些冗余的class合并到superclass或subclass中,或者通过Inline Class(与Extract Class相反),将这些冗余class中的所有Method/Field迁移到其他相关的class中。

 

13Speculative Generality(夸夸其谈未来性)

现象:系统中出现一些无用的abstract class,或者非必要的delegation(委托),或者多余的参数等等。

重构策略:分别使用Collapse Hierarchy合并abstract class,使用Inline Class移除非必要的delegation,使用Remove Parameter删除多余的参数。

 

14Temporary Field(令人迷惑的暂时值域)

现象:class中存在一些Field,这些Field只在某种非常特定的情况下需要。

重构策略:通过Extract Class将这些孤独的Field及其相关的Method移植的一些新的Class中。提炼出来的新Class可能没有任何抽象意义,只是提供Method的调用,这些新Class一般称为Method Object。

 

15Message Chains(过度耦合的消息链)

现象:向一个对象请求另一个对象,然后再向后者请求另一个对象,……,这就是Message Chain,意味着Message Chain中任何改变,将导致Client端不得不修改。

重构策略:通过Hide Delegate(隐藏委托关系)消除Message Chain,具体做法是在Message Chain的任何地方通过Extract Method建立一个简单委托(Delegation)函数,来减少耦合(Coupling)。

 

16Middle Man(中间转手人)

现象:过度运用delegation,某个/某些Class接口有一半的函数都委托给其他class,这样就是过度delegation。

重构策略:运用Remove Middle Man,移除简单的委托动作(也就是移除委托函数),让client直接调用delegate受托对象。和上面的Hide Delegate(隐藏委托关系)刚好相反的过程。

 

由于系统在不断的变化和调整,因此[合适的隐藏程度]这个尺度也在相应的变化,Hide Delegate和Remove Middle Man重构策略可以系统适应这种变化。

 

另外,可保留一部分委托关系(delegation),同时也让Client也直接使用delegate受托对象。

 

17Inappropriate Intimacy(狎昵关系)

现象:两个Class过分亲密,彼此总是希望了解对方的private成分。

重构策略:可以采用Move Method和Move Field来帮助他们划清界限,减少他们之间亲密行为。或者运用Change Bidirectional Association to Unidirectional,将双向关联改为单向,降低Class之间过多的依存性(inter-dependencies)。或者通过Extract Class将两个Class之间的共同点移植到一个新的Class中。

 

18Alternative Classes with Different Interfaces(异曲同工的类)

现象:两个函数做相同的事情,却有不同的signature。

重构策略:使用Rename Method,根据他们的用途来重命名。另外,可以适当运用Move Method迁移某些行为,使Classes的接口保持一致。

 

19Incomplete Library Class(不完美的程序库类)

现象:Library Class(类库)设计不是很完美,我们需要添加额外的方法。

重构策略:如果可以修改Library Class的Source Code,直接修改最好。如果无法直接修改Library Class,并且只想修改Library Class内的一两个函数,可以采用Introduce Foreign Method策略:在Client Class中建立一个函数,以外加函数的方式来实现一项新功能(一般而言,以server class实例作为该函数的第一个参数)。

 

如果需要建立大量的额外函数,可应该采用Introduce Local Extension:建立一个新class,使它包含额外函数,并且这个class或者继承或者wrap(包装)source class。

 

20Data Class(纯稚的数据类)

现象:Data Class指:一些Class拥有Fields,以及用来访问Fields的getter/setter函数,但是没有其他的功能函数。(感觉这些Data Class如同Entity Class或Parameter Class,用来传递参数,我认为这种情况下没有必要重构。)

重构策略:找出其他class中访问Data Class中的getter/setter的函数,尝试以Move Method将这些函数移植到Data Class中,实现将数据和操作行为(方法)包装在一起,也让Data Class承担一定的责任(方法)。

 

21Refused Bequest(被拒绝的遗赠)

现象:Subclass不想或不需要继承superclass的部分函数和Field。

重构策略:为subclass新建一个兄弟(sibling class),再运用Push Down Method和Push Down Field将superclass中的相应函数和Field下推到兄弟class,这样superclass就只包含subclass共享的东西了。其实,也就是将superclass中一些与特定的函数和Field放到特定的subclass中,superclass中仅包含subclass共享的函数和Field。

 

如果不想修改superclass,还可以运用Replace Inheritance with Delegation来达到目的。也就是以委托取代继承,在subclass中新建一个Field来保存superclass对象,去除subclass对superclass的继承关系,委托或调用superclass的方法来完成目的。

 

22Comments(过多的注释)

现象:(晕倒,这个也要重构,Remove掉所有的Comments吗?不是。)当代码中出现一段长长的注释,一般是由于代码比较糟糕,需要进行重构,除去代码的坏味道。

重构策略:通过上面提及的各种重构策略,将代码的坏味道去除,使注释变成多余。

如果需要注释/解释一段代码做了什么,则可以试试Extract Method,提取出一个独立的函数,让函数名称解释该函数的用途/功能。另外,如果觉得需要注释来说明系统的某些假设条件,

也可尝试使用Introduce Assertion(引入断言),来明确标明这些假设。

 

当你感觉需要撰写注释时,请先尝试重构,试着让所有的注释都变得多余。

 

代码的坏味道(Bad Smell in Codes)学习完了,走完了第一步。后面的内容也翻过多次,感觉还是蛮好懂的。嗯,今天掌握了挑别人代码毛病的精锐武器。郁闷的是,自己写的代码也需要重构。


http://www.cnblogs.com/rickie/archive/2004/12/14/76663.html

Statement
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
如何解决Python的代码的可维护性差错误?如何解决Python的代码的可维护性差错误?Jun 25, 2023 am 11:58 AM

Python作为一门高级编程语言,在软件开发中得到了广泛应用。虽然Python有许多优点,但很多Python程序员经常面临的问题是,代码的可维护性较差。Python代码的可维护性包括代码的易读性、可扩展性、可重用性等方面。在本篇文章中,我们将着重讨论如何解决Python代码的可维护性差的问题。一、代码的易读性代码可读性是指代码的易读程度,它是代码可维护性的核

如何做好Java代码的重构如何做好Java代码的重构Jun 15, 2023 pm 09:17 PM

作为世界上最流行的编程语言之一,Java已成为许多企业和开发者的首选语言。然而,代码的重构对于保持代码质量以及开发效率至关重要。Java代码由于其复杂性,随着时间的推移可能会变得越来越难以维护。本文将讨论如何进行Java代码的重构,以提高代码质量和可维护性。了解重构的原则Java代码重构的目的在于改进代码的结构、可读性和可维护性,而不是简单的“改变代码”。因

提高Python代码可读性的五个基本技巧提高Python代码可读性的五个基本技巧Apr 11, 2023 pm 09:07 PM

译者 | 赵青窕审校 | 孙淑娟你是否经常回头看看6个月前写的代码,想知道这段代码底是怎么回事?或者从别人手上接手项目,并且不知道从哪里开始?这样的情况对开发者来说是比较常见的。Python中有许多方法可以帮助我们理解代码的内部工作方式,因此当您从头来看代码或者写代码时,应该会更容易地从停止的地方继续下去。在此我给大家举个例子,我们可能会得到如下图所示的代码。这还不是最糟糕的,但有一些事情需要我们去确认,例如:在load_las_file函数中f和d代表什么?为什么我们要在clay函数中检查结果

如何解决Python的代码中的代码复杂度过高错误?如何解决Python的代码中的代码复杂度过高错误?Jun 24, 2023 pm 05:43 PM

Python是一门简单易学高效的编程语言,但是当我们在编写Python代码时,可能会遇到一些代码复杂度过高的问题。这些问题如果不解决,会使得代码难以维护,容易出错,降低代码的可读性和可扩展性。因此,在本文中,我们将讨论如何解决Python代码中的代码复杂度过高错误。了解代码复杂度代码复杂度是一种度量代码难以理解和维护的性质。在Python中,有一些指标可以用

Go语言中的优化和重构的方法Go语言中的优化和重构的方法Jun 02, 2023 am 10:40 AM

Go语言是一门相对年轻的编程语言,虽然从语言本身的设计来看,其已经考虑到了很多优化点,使得其具备高效的性能和良好的可维护性,但是这并不代表着我们在开发Go应用时不需要优化和重构,特别是在长期的代码积累过程中,原来的代码架构可能已经开始失去优势,需要通过优化和重构来提高系统的性能和可维护性。本文将分享一些在Go语言中优化和重构的方法,希望能够对Go开发者有所帮

深入理解Go语言中的函数重构技巧深入理解Go语言中的函数重构技巧Mar 28, 2024 pm 03:05 PM

在Go语言程序开发中,函数重构技巧是十分重要的一环。通过优化和重构函数,不仅可以提高代码质量和可维护性,还可以提升程序的性能和可读性。本文将深入探讨Go语言中的函数重构技巧,结合具体的代码示例,帮助读者更好地理解和应用这些技巧。1.代码示例1:提取重复代码片段在实际开发中,经常会遇到重复使用的代码片段,这时就可以考虑将重复代码提取出来作为一个独立的函数,以

Python开发经验分享:如何进行代码重构和优化Python开发经验分享:如何进行代码重构和优化Nov 22, 2023 pm 07:25 PM

Python开发经验分享:如何进行代码重构和优化引言:随着软件开发的不断发展,代码的重构和优化已成为开发过程中不可或缺的一环。而Python作为一门动态、简洁的高级编程语言,也同样需要进行代码重构和优化来提高程序的性能和可维护性。本文将分享一些Python代码重构和优化的经验,帮助开发者写出更高效、更可靠的Python代码。第一部分:代码重构代码重构是指对已

Go语言中的该如何进行代码重构Go语言中的该如何进行代码重构Jun 02, 2023 am 08:31 AM

随着软件开发的不断深入和代码的不断积累,代码重构已经成为了现代软件开发过程中不可避免的一部分。它是一种对系统的既定代码进行修改,以改善其结构、性能、可读性或其他相关方面的过程。在本文中,我们将探讨如何在Go语言中进行代码重构。定义好重构的目标在开始代码重构之前,我们应该制定一个清晰的重构目标。我们需要问自己一些问题,比如这段代码存在哪些问题?我们要通过重构

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
2 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Repo: How To Revive Teammates
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island Adventure: How To Get Giant Seeds
4 weeks agoBy尊渡假赌尊渡假赌尊渡假赌

Hot Tools

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

Powerful PHP integrated development environment

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),