修改代码的艺术, part 1

      2年前在实习的时候买了这本书,当时就随便翻了翻,也没看懂太多;  最近比较轻松,碰巧比较关注代码质量,一口气就把这书读完了。 这本书虽然关注点比较窄(重构代码,解开依赖,方便测试),但在这方面就众多情形提出了各自的解决方案,不得不说作者富有相当的代码洞察能力和实践经验。总的来说是本好书。

      下面是我自己的一点体会:

PⅠ,概念和原则

      1.  测试有关

            测试代码并不难写, 它毕竟也只是代码, 胡乱一通总可以得到个结论, 但如果这样做, 也许我们还得需要额外的东西来测试我们的测试代码; 同样由于只是代码, 我们就有大量可以展现其漂亮的方式. 编写测试代码比较困难的一个因素就是测试对象内部与其外部的依赖.

            假设我们现在完成了一个典型的3层系统, 如果我们需要测试逻辑层是否正确, 正式产品的运作方式是需要向下访问数据层的, 这里多半需要提供数据库的连接, 但由于层次的明确, 如果我们测试时获取数据的方式同样采取访问产品的数据层, 那么一方面, 设置数据层环境并不那么容易, 我们需要付出额外的工作代价; 另一方面, 如果测试失败, 由于我们引入了另外的层次, 错误将难定位.

            测试就是给定语义上下文合理的输入, 执行测试方法, 比较实际输出和语义逻辑输出.

            方便的测试就是除去所有复杂无意义的依赖, 实例化测试类(产品类的去依赖版本), 运行其上复写的简易方法, 然后实际结果与意义上的逻辑结果比较.

    2. 本书有关

            接缝: 指程序中的一些特殊点, 在这些点上你无需作任何修改就可以达到改变程序行为的目的. 面象对象方面, 虚函数就是一种接缝.  

    3. 解决方案

            本书就是围绕这类主题, 其提出的各种解决方案本质都是寻找适当的接缝, 引入中间层(通常是接口), 以解除测试对象有关的各种依赖.

 

PⅡ, 具体技巧

      1. 接口提取

      原始代码: TargetFun是我们要测试的方法, 它依赖了DependenceObj的Fun函数.

 1Class TargetCls
 2{
 3    public void TargetFun()
 4        {
 5           
 6
 7           DependenceObj obj = new DependenceObj();
 8           obj.Fun();
 9
10           
11        }

12}

      重构: TestFun是我们与TargetFun配套的测试方法, 其实现基本一样, 区别仅仅是IObj指向对象不同.

Code

    这个例子存在代码重复, 下面的方法可以避免这个问题.

    2. 参数化

    原始代码:

 1Class TargetCls
 2{
 3    public void TargetFun()
 4    {
 5       
 6    
 7       DependenceObj obj = new DependenceObj();
 8       obj.Fun();
 9
10         
11    }

12}

      重构: 

Code

     对于由于依赖难以执行的方法都可以尝试此技巧. 比如某构造函数内部依赖严重难以创建此类型对象, 我们可以将依赖对象由外部传入, 测试时只需要传入简单对象即可. 为了保持一致性, 带参数方法多作为原方法委托实现.

    3. 子类化并重写

    原始代码: 

Code

    重构:

Code

    为了可以override依赖方法, 此方法必须声明virtual, 并提升访问权限.

    4. 方法分解, 子类化

    原始代码:

Code

    重构: 

Code

    分解巨型方法是关键.

 5. 剥离并外覆

    子类化是一个重要的解依赖手段, 但有时候由于特殊原因,  被依赖的类不能被继承(sealed).

    原始代码:

 1sealed class UninheritCls
 2{
 3
 4}

 5
 6class TargetCls
 7{
 8    public void TargetFun(UninheritCls obj)
 9    {
10        
11        obj.Fun();
12        
13    }

14}

     重构: 

Code

 

posted @ 2009-06-23 15:05  Tyrael  阅读(345)  评论(0编辑  收藏  举报