吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2677|回复: 2
收起左侧

[Java 转载] 《重构-改善既有代码设计》【2-4】章整理学习分享(重构原则,junit测试)

[复制链接]
象相合 发表于 2017-12-2 14:46
        这篇文章整合了《重构-改善既有代码设计》2-4章的一些信息。主要有
               1. 分析整理的重构原则。
               2. 重构的手法场景介绍。
               3. Junit测试的使用方式。
        分享给大家,希望大家不要直接点收藏就关了,全部浏览一遍,可以在潜意识中酝酿这些大神们积淀多年的智慧。
        有条件的同学,可以直接下载电子书,自己看一遍原本收获更多。

         一、分析整理的重构原则。
  • 为即将修改的代码建立一组可靠的测试环境。
  • 临时变量助长冗长而复杂的函数。
  • 最好不要再另一个对象的属性基础上运用switch语句。如果要switch也要在类自己的数据上使用。
  • 事不过三,三则重构。
  • 首先写出可调的程序,然后调整它以求获得足够速度。
  • 一个好的名字可以省去读函数内容的操作。
  • 每当需要注释说明时,可以被写进一个函数里,并以用途命名,关键不在函数长度,而在函数做什么,怎么做。
  • 条件和循环也是提炼信号。
  • 针对外界变化的所有相应修改,应该只发生在单一类中,这个类的所有内容随外界变化。
  • 一个函数使用几个类的功能,它应该被放在最多被此函数使用的数据一起。
  • 对于出现在不同类/方法内的一些绑在一起的数据,应该给它们设置对象。
  • 少用switch,switch代表重复。
  • 两个帽子原则:不要边写代码边重构,带上写代码的帽子,觉得需要重构了,再带上重构的帽子去做,如此反复。
  • 注释多写为什么这样,过多注释不一定是好,尝试重构。
  • 先编写测试代码可以将关注点放在接口而非实现。
  • 每当出现一个BUG,先写一个测试单元测试BUG。不要修改以前的测试单元,因为它可能会在修复BUG后出错。
  • 测试:异常,边界
  • 测试太多带来的效益呈现递减态势。但是我们尽量测试大多数BUG。


          二、重构的手法场景介绍。【由于IDE里使用的是英文,因此了解每一个英文意义尤为重要。

  • Duplicated Code
  • 同一个类两个函数有相同表达式:Extract Method(110) 提炼相同代码。
  • 互为兄弟子类内含有相同表达式:Extract Method(110) -> Pull Up Method(332) 推入超类 ->Form Template Method(345) 获得Template Method设计模式 -> Substitute Algorithm(139)替换算法。
  • 毫不相关的类:Extract Class(149)

  • Long Method
  • 99%场合使用:Extract Method(110)找到适合在一起的提炼即可。
  • 有大量参数和临时变量:Replace Temp with Query(120)消除临时变量,Introduce Parameter Object(295)和Preserve Whole Object(288)可将过长参数列变简洁。还不行就用Replace Method with Method Object(135)。
  • 条件和循环时:Decompose Conditional(238)处理条件。Extract Method(110)处理循环。

  • Large Class
  • 类太大:Extract Class(149)甚至可以Extract Subclass(330)提取子类。先确定客户端如何使用他们,再运用Extract Interface(341)为每一个使用方式提炼一个接口。这可以帮助看清如何分解类。
  • 如果是个GUI类:使用Duplicate Observed Data(189)。

  • Long Parameter List过长参数列
  • 如果向已有对象发出一条请求就可以取代一个参数,使用Replace Parameter with Method(292)。
  • 使用Preserve Whole Object(288)将同一对象的数据收集起来,并以对象替换。
  • 缺乏合理对象归属:使用Introduce Parameter Object(295)制造参数对象。

  • Divergent Change发散式变化
  • 一个类受多个变化的影响:Extract Class(149)

  • Shotgun Surgery霰弹式修改
  • 每遇到一个变化,要在不同类做修改:Move Method(142)和Move Field(146)把需要修改的代码放进同一个类。使用Inline Class(154)把一系列相关行为放进一个类。

  • Feature Envy依恋情结
  • 函数为了计算某个值,从另一个对象调用一堆取值函数:把这个使用Move Method(142)把它移到该去的地方。使用Extract Method(110)把这一部分提炼到独立函数,使用Move Method(142)放在该去的地方。如果有多个类的功能,使用Extract Method(110)分解为多个小函数,再放在调用最多数据的类里。

  • Data Clumps数据泥团
  • 对于多个地方绑定在一起的数据:使用Extract FClass(149)将他们提炼到一个独立对象。然后转到函数签名,使用Introduce Parameter Object(295)或Preserve Whole Object(288)为他减肥。这样可以简化调用。

  • Primitive Obsession基本类型偏执
  • 对象可以在小类型创建小对象:使用Replace Data Value with Object(175)进入对象世界。
  • 替换的数据值是类型码,并不影响行为:使用Replace Type Code with Class(218)
  • 与类型码相关的条件表达式:使用Replace Type Code with Subclass(213)或Replace Type Code wtih State/Strategy(227)处理。
  • 总被放一起的字段:使用Extract Class(149)
  • 参数列看到基本型数据:使用Introduce Parameter Object(295)。
  • 从数组中挑选数据:使用Replace Array with Object(186)

  • Switch Statements:Switch惊悚现身
  • 使用多态代替Switch:Extract Method(110)->Move Method(142)->Replace Type Code with Subclasses(223)或Replace Type Code with State/Strategy(227)完成继承结构->Replace Conditional with Polymorphism(255)
  • 如果是单一函数的选择示例:使用Replace Parameter with Explicit Method(285)
  • 如果选择条件有null:使用Introduce Null Object(260)

  • Parallel Inheritance Hierarchies平行继承体系
  • 每当为某各类增加子类,也要为另一个类增加子类:让继承体系的实例引用另一个继承体系的实例。再使用Move Method(142)和Move Field(146)。


  • Lazy Class冗赘类
  • 一个类变得不再有价值:使用Collapse Hierarchy(344)和Inline Class(154)。

  • Speculative Generality夸夸其谈未来性
  • 对于未来可能会有的方法或类:如果它没被用到,使用Collapse Hierarchy(344)或Inline Class(154)。
  • 某些参数未被使用:Remove Parameter(154)
  • 函数名称有多余抽象意味:Rename Method(273)

  • Temporary Field令人迷惑的暂时字段
  • 某个实例变量仅因特定情况而设:使用Extract Class(149)提取这个情况并把相关代码放进去。也可以用Introduce Null Object(260)在“变量不合法”的情况创建Null对象。
  • 复杂算法需要好几个变量:Extract Class(149)把这些变量和其他相关函数提炼到一个类作为函数对象Beck。


  • Message Chains过度耦合的消息链
  • 一个对象请求一个对象又请求一个对象…:使用Hide Delegate(157) 可以在消息链不同位置使用。更好的做法:Extract Class(149)提炼到一个函数,Move Method(142)推入消息链。

  • Middle Man中间人
  • 过度委托:使用Remove Middle Man(160)和负责的对象打交道。运用InlineMethod(117)放进调用端。如果Middle Man还有其他行为,使用Replace Delegation with Inheritance(355)变成实责对象子类,就可以扩展原对象行为。

  • Inappropriate Intimacy狎昵关系
  • 两个类过去亲密:使用Move Method(142)和Move Field(146)划清界限。或使用Change Bidirectional Association to Unidirectional(200)让一个类斩断关系。Extract Class(146)提炼到一个安全地点。或使用Hide Delegate(157)

  • Alternative Classes with Different Interfaces异曲同工的类
  • 两个函数做同一件事,却有不同签名。使用Rename Method(273)根据用途命名。使用Move Method(142)将某些行为移入类直到协议相同。使用Extract Superclass(336)可以减少重复冗余代码。

  • Incomplete Library Class不完美的库类
  • 修改库类的函数:使用Introduce Foreign Method(162)
  • 添加额外行为:使用Introduce Local Extension(164)

  • Data Class纯稚的数据类
  • 有一些用于访问(读写)字段的函数,其他类过分操作它们:使用Encapsulate Field(206)封装对不该被其他类修改的字段,使用Remove Setting Method(300)对这些点Move Method(142)把它们调到Data Class不能搬移整个就搬部分,不久就可以使用Hide Method(303)把它们隐藏。

  • Refused Bequest被拒绝的遗赠
  • 继承设计错误:新建兄弟类,使用Push Down Method(328)和Push Down Field(329)把用不到的推给兄弟类。超类只持有所有子类共享的东西。
  • 子类复用了超类行为,却又不愿意支持超类接口:使用Replace Inheritance with Delegation(352)达到目的。

  • Comments过多注释
  • 太多注释意味着坏味道:使用Extract Method(110),还需要注释的话使用Rename Method(273),如果需要注释需求使用Introduce Assertion(267)


         三、Junit测试的使用方式。

        上github:https://github.com/EleComb/Reconstruction
        如果你不知道github怎么用,看这里或官方文档

        OK,今天的分享就是这些了,祝大家学习进步!

免费评分

参与人数 2吾爱币 +3 热心值 +2 收起 理由
GA゛木子 + 2 + 1 用心讨论,共获提升!
junnyfei + 1 + 1 用心讨论,共获提升!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

junnyfei 发表于 2017-12-2 14:52
这么牛逼,学习了。。。
fq645122 发表于 2017-12-2 15:18
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-16 01:08

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表