第三章 代码的味道
DuplicatedCode(重复代码)
- 同一个类的两个函数含有相同的表达式
- 两个互为兄弟的子类含有相同表达式
- 两个毫不相干的类出现重复代码
LongMethod(过长函数)
- 函数不宜过长,函数越长越难理解
- 如果想利用单个类做太多事情,其内往往就会出现大量实例变量,会导致大量重复代码
LongParameterList(过长参数列)
- 太长的参数列难以理解,太多参数容易造成前后不一致,不易使用
DivergentChange(发散式变化)
- 如果某个类经常因为不同的原因在不同方向上发生变化,发散式变化就出现了
ShotgunSurgery(霰弹式修改)
- 如果每遇到某种变化,都必须在许多不同的类内做出许多小修改。如果需要修改的代码散步四处,不但很难找到它们,也很容易忘记某个重要的修改
FeatureEnvy(依恋情结)
- 将数据和对数据的操作行为包装在一起的技术
DataClumps(数据泥团)
- 有地方出现相同的三四项数据:两个类中相同的字段、许多函数签名中相同的参数
PrimitiveObsession(基本类型偏执)
- 如果只为做一两件事而创建结构类型会显得多余
SwitchStatements(switch惊悚现身)
- switch语句问题在于重复,尽可能用多态来替代
ParallelInheritanceHierarchies(平行继承体系)
- 属于ShotgunSurgery的特殊情况,每当你为某个类增加一个子类,必须也为另一个类相应增加一个子类
LazyClass(冗赘类)
- 一个没有任何其价值的类(没有地方有调用到)
SpeculativeGenerality(夸夸其谈未来性)
- 过度设计,企图以各种各样的钩子和特殊情况来处理一些非必要的事情
TemporaryField(令人迷惑的暂时手段)
- 某个实例变量仅为某种特定情况而设
MessageChains(过渡耦合的消息链)
- 客户端代码与查找消息过程中的导航结构紧密耦合
MiddleMan(中间人)
- 过度运用委托类
InappropriateIntimacy(狎昵关系)
- 两个类联系过度紧密,需要花费太多时间去探究彼此的private成分
AlternativeClassWithDifferenceInterfaces(异曲同工类)
- 两个函数做同一件事
IncompleteLibraryClass(不完美的库类)
- 复用程序库的类并修改其中的类使它完成我们希望完成的工作
DataClass(纯稚的数据类)
- 拥有一些字段,以及用于访问(读写)这些字段的函数,除此之外一无长处
RefusedBequest(被拒绝的馈赠)
- 利用继承来复用一些行为,并发现可以很好地应用于日常工作
Comments(过多的)
- 一段代码中有着长长的注释
第四章
自测试代码的价值
- 一套测试就是一个强大的bug侦测器,能够大大缩减查找bug所需要的时间
- 撰写测试代码的最有用时机是在开始编程之前
Junit测试框架
-
创建一个FileReaderTester类来测试文件读取器。任何包含测试代码的类(即测试用例)都必须继承测试框架所提供的TestCase类
-
重构过程中,可以只运行少数几项测试,主要用来检查当下正在开发或整理的代码
-
在测试失败的时候,或可以用断言,让错误信息更清楚
-
编写测试代码时,往往一开始先让它们失败。把失败和错误区分出来,用于不同情况下的排除问题
-
Junit框架的用途时单元测试
- 单元测试(Unit Test)和功能测试(FunctionalTest)之间的差异
- 单元测试更能提高程序员的生产率
- 单元测试属于高度局部化的东西,与其他包相互独立
- 功能测试时用来保证软件能够正常运作,从客户的角度保障质量,并不关心程序员的生产力
- 功能测试尽可能把整个系统当做一个黑箱(黑盒测试)
- 单元测试(Unit Test)和功能测试(FunctionalTest)之间的差异
-
Junit框架设计用来编写单元测试,功能测试往往以其他工具辅助进行
添加更多测试
- 观察类该做的所有事情,然后针对任何一项功能的任何一种可能失败的情况,进行测试
- 编写未臻完善的测试并实际运行,好过对完美测试的无尽等待
- 考虑可能出错的边界条件,把测试火力集中在那里
- 当事情被认为应该会出错时,别忘了检查是否抛出了预期的异常
- 不要因为测试无法捕捉所有bug就不写测试,因为测试的确可以捕捉到大多数的bug