重构(Refactoring)技巧读书笔记 之二

news/2024/5/18 22:57:38 标签: refactoring, 读书, class, primitive, object, borland
class="baidu_pl">
class="article_content clearfix">
class="htmledit_views">

转自:http://www.cnblogs.com/rickie/archive/2004/10/04/48859.html

本文继续《重构( Refactoring )技巧class="tags" href="/tags/DuShu.html" title=读书>读书笔记 之一 》,重构的确是未来软件工程师需要掌握的一项技能。目前一些支持 .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 )及其重构策略
5 Divergent Change (发散式变化)
现象:当某个 Class 因为外部条件的变化或者客户提出新的功能要求等时,每次修改要求我们更新 Class 中不同的方法。不过这种情况只有在事后才能觉察到,因为修改都是在事后发生的么(废话)。
重构策略:将每次因同一条件变化,而需要同时修改的若干方法通过 Extract Class 将它们提炼到一个新 Class 中。实现目标是:每次变化需要修改的方法都在单一的 Class 中,并且这个新的 Class 内所有的方法都应该与这个变化相关。
 
6 Shotgun Surgery (霰弹式修改)
现象:当外部条件发生变化时,每次需要修改多个 Class 来适应这些变化,影响到很多地方。就像霰弹一样,发散到多个地方。
重构策略:使用 Move Method Move Field Class 中需要修改的方法及成员变量移植到同一个 Class 中。如果没有合适的 Class ,则创建一个新 Class 。实现目标是,将需要修改的地方集中到一个 Class 中进行处理。
 
比较 Divergent Change (发散式变化)和 Shotgun Surgery (霰弹式修改):
前者指一个 Class 受到多种外部变化的影响。而后者指一种变化需要影响到多个 Class 需要修改。都是需要修理的对象。
 
7 Feature Envy (依恋情结)
现象: Class 中某些方法“身在曹营心在汉”,没有安心使用 Class 中的成员变量,而需要大量访问另外 Class 中的成员变量。这样就违反了对象技术的基本定义:将数据和操作行为(方法)包装在一起。
重构策略:使用 Move Method 将这些方法移动到对应的 Class 中,以化解其“相思之苦”,让其牵手。
 
8 Data Clumps (数据泥团)
现象:指一些相同数据项目( Data Items ),如 Class 成员变量和方法中参数列表等,在多个 Class 中多次出现,并且这些数据项目有其内在的联系。
重构策略:通过使用 Introduce Parameter Object (创建新的参数对象取代这些参数)或 Preserve Whole Object (使用已存在的对象取代这些参数),实现使用对象代替 Class 成员变量和方法中参数列表,清除数据泥团,使代码简洁,也提高维护性和易读性。
 
9 Primitive 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 两个新类。
 
10 Switch Statements Switch 语句)
现象:同样的 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 语句时,才应该考虑进行重构。
 

 


http://www.niftyadmin.cn/n/1148748.html

相关文章

git 无法pull,There is no tracking information for the current branch.

在执行git pull的时候,提示当前branch没有跟踪信息: git很智能,下面提示提供了解决办法: 两种情况如下: 就比如说要操作master吧,一种是直接指定远程master: git pull origin master 另外一种方…

分享:selenium(一) xpath

xpath无所不能定位。 https://www.w3.org/TR/xpath/all/#axes 两个神器:firebug、xpath-checker举例:混合定位//td[a//front[contains(text(),"从零开始视频")]//input[typecheckbox]确认xpath是否是正确的:firefox>F12>控…

微信公众号开发——接口配置信息的开发

开篇先吐槽一下微信公众号开发官方文档,看的真累 接口配置信息 文档地址 EncodingAESKey 暂时不需要处理,用于加密解密消息的 配置url 这个url用户接收和被动回复用户消息。微信会调用这个url,故需要可以外网访问 接口实现 查看文档: requ…

技术沙龙|“智能之约,链动未来”——区块链下的创新思考(深圳)

2019独角兽企业重金招聘Python工程师标准>>> 到了2018年下半年,越来越多的传统开发者转入区块链开发行业,当初学者了解了智能合约、超级账本之后不禁有一个疑惑,区块链Dapp开发和传统APP开发,除了多了Token&#xff0c…

高新区:从服务外包泥瓦匠到自主创新工程师

“在软件行业,发展中国家只是‘泥瓦工’,但是我希望有一天我们也成为‘建筑师’。”这是3年前,市长 夏德仁接受托马斯弗里德曼专访时的心愿。现在的大连高新区,已涌现出越来越多的“建筑师”,大批自主研发的软件产品相…

微信公众号开发——接收用户消息和回复消息

接收用户消息和回复消息 接收用户消息 文档地址:接收普通消息消息类型 文本 图片 语音 视频 视频 地理位置 回复消息 文档地址:被动回复用户信息文本回复 图片 **这里只展开文本和图片,其他几种类型用法相似** 代码 url地址…

mysql数据库修改密码方法

环境介绍:操作系统:Red Hat linux6数据库版本:Mysql5.7 注:MySQL5.7在初始安装后,会生成随机初始密码,并在/var/log/mysqld.log中有记录,可以通过head命令查看,找password关键字即可…