《重构 改善既有代码的设计》之重构原则

1 简介

过年回家了,在家里已经呆了两天,两天里陪父母烧锅,教他们使用红米手机,聊天,吃饭。家里很好,只是父母年纪又大了一岁,很心疼它们,听他们讲年后还要出去打工挣钱,不知道说什么,觉得很对不起他们。我真的是太没用了。父亲总是吸烟,烟瘾很重,一晚上要吸很多根,我很担心,但总是劝不停。两天没有总结这本刚看完的《重构》了,所以今晚上,虽然很冷,还是坐在椅子边上认真的敲一些字,总结一下吧。
重构 改善既有代码的设计第二章主要讲述的是重构的整体的含义、作用,主要是回答了重构的定义、重构的原因、重构何时进行,以及重构的难点,重构与性能之间的考量。
二话不说,先上总结的XMind。
《重构 改善既有代码的设计》之重构原则_第1张图片
这是本章的梗概。

2 重构原则

使用XMind总结本章的主要内容,在各个小节可以看到如下的内容:
《重构 改善既有代码的设计》之重构原则_第2张图片
大体内容如上。

3 重构定义

重构的定义主要有两种形式,一种名次形式,一种动词形式。
名次形式如下:

对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其理解性,降低其修改成本。

一般而言,重构都是对软件的小改动。诸如Extrac Class, Move Method, Move Field.
动词形式如下:

使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。
需要强调的是,重构不会改变软件可观察的行为----重构之后软件功能一如往常。

两顶帽子:
重构和添加功能,两者关系如下:

添加新功能时,你不应该修改既有代码,只管添加新功能。重构时就不能再添加功能,只管改进程序结构

4 为何重构

重构可以帮助程序员始终良好的控制自己的代码。重构可以并且应该用于以下几个目的

4.1 重构改进软件设计

程序一般在不断的修改中,程序会逐渐失去自己的结构,程序员会越来越难以通过阅读源码而理解原来的设计,重构很像是整理代码
设计不良的程序往往需要更多代码,这常常是因为代码在不同的地方使用完全相同的语句做同样的事,因此改进设计的一个重要方向就是消除重复代码
如果消除重复代码,就可以确定所有事物和行为在代码中只表述一次,这正是优秀代码的设计。

4.2 重构使软件更容易理解

应该稍微改变一下开发节奏,对代码做适当修改,让代码变得更易理解。

4.3 重构帮助找到bug

Kent Beck经常形容自己的一句话:“我不是个伟大的程序员,我只是个有着一些优秀习惯的好程序员。”

4.4 重构提高编程速度

改善错误
提升可读性
减少错误

良好的设计是快速开发的根本,重构可以帮助你更快速地开发软件,因此它阻止系统腐败变质,甚至可以提高设计的质量。

4.5 何时重构

几乎任何情况下都反对专门拨时间进行重构,重构应该随时随地进行

三次法则

第一次做某件事只管去做,第二次做类似的事情会产生反感,但无论如何还是可以去做;第三次再做,不,你应该进行重构

重构的时机
1. 添加功能时重构
1. 修补错误时重构
1. 复审代码时重构
如果能够得到别人的帮助,我的生活会滋润得多,所以我总是期待更多复审
用UML展现设计
重构为什么有用

两个问题

今天可以为你做什么?
明天可以为你做什么?

间接层和重构的重要性

程序难以相与的原因
 难以阅读的程序,难以修改
 逻辑重复的程序,难以修改
 添加新行为时需要修改已有代码的程序,难以修改
 带复杂条件逻辑的程序,难以修改
良好的程序
 容易阅读
 所有的逻辑只在唯一地点指定
 新的改动不会波及现有行为
 尽可能简单表达条件逻辑

4.6 重构与性能

在Java编程思想中,Bruce Eckel说不要过早关注程序效率,这是个诱人的陷阱,最好是首先让程序运行起来,再考虑速度。

除了对性能有严格要求的实时系统,其他任何情况下,编写“快速软件”的秘密是:首先写出可调的软件,然后调整它以求获得足够的速度。

两种表述如出一辙。

    public String statement() {
       double totalAmount = 0;
       int frequentRenterPoints = 0;
       Enumeration rentals = _rentals.elements();
       String result = "Rental Record for " + getName() + "\n";
       while (rentals.hasMoreElements()) {
          Rental rental = (Rental) rentals.nextElement();
          frequentRenterPoints += rental.getFrequentRenterPoints();
          // show figures for this rental
          result += "\t" + rental.getMovie().getTitle() + "\t"
                + String.valueOf(rental.getCharge()) + "\n";
          totalAmount += rental.getCharge();
       }
       // add footer lines
       result += "Amount owed is " + String.valueOf(totalAmount) + "\n";
       result += "You earned " + String.valueOf(frequentRenterPoints)
             + " frequent renter points";
       return result;
    }

在第一章案例1中,去除临时变量之后可以看到statement()函数如下:
可以看到在处理getTotalCharge()和getTotalFrequentRenterPoints()函数过程中,使用了Replace Temp with Query两个函数,

    public String statement() {
       int frequentRenterPoints = 0;
       Enumeration rentals = _rentals.elements();
       String result = "Rental Record for " + getName() + "\n";
       while (rentals.hasMoreElements()) {
          Rental each = (Rental) rentals.nextElement();
          frequentRenterPoints += each.getFrequentRenterPoints();
          // show figures for this rental
          result += "\t" + each.getMovie().getTitle() + "\t"
                + String.valueOf(each.getCharge()) + "\n";
       }
       // add footer lines
       result += "Amount owed is " + String.valueOf(getTotalCharge()) + "\n";
       result += "You earned " + String.valueOf(getTotalFrequentRenterPoints())
             + " frequent renter points";
       return result;
    }

在这个过程中使用了类似的重构,即由于totalAmount和frequentRenterPoints均位于循环内部赋值,所以在重构过程中不得不把循环复制到查询函数中。

    // 译注:此即所谓query method
    private int getTotalFrequentRenterPoints() {
       int result = 0;
       Enumeration rentals = _rentals.elements();
       while (rentals.hasMoreElements()) {
          Rental each = (Rental) rentals.nextElement();
          result += each.getFrequentRenterPoints();
       }
       return result;
    }

可以看到这次重构存在一个问题,即性能,

原本代码只执行while循环一次,新版本要执行三次,如果while耗时很多,就可能大大降低程序的性能。单单为了这个原因,很多程序员就不愿进行这个重构动作。但是请注意我的用词,”如果”和“可能”。除非我进行评测,否则我无法确定循环的执行时间,也无法知道这个循环是否被经常使用以至于影响系统的整体性能。重构时你不必担心这些,优化时你才需要担心它们,但那时候你已经处于一个比较有利的位置,有更多的选择可以完成有效优化。

5 总结

在重构这本书中,这一章主要阐明了重构的原因、时机以及重构与性能之间的问题和关系。尤其重构定义,最好能够背诵并深刻理解,这样才能真正的理解重构原理。

6 参考

参考

《重构 改善既有代码的设计》之重构原则
《重构 改善既有代码的设计》之重构,第一个案例详解
《重构 改善既有代码的设计》之JUnit测试框架以及IDEA与JUnit整合
《重构 改善既有代码的设计》之代码的坏味道
《重构 改善既有代码的设计》之重构列表

你可能感兴趣的:(读后感)