热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

1简介过年回家了,在家里已经呆了两天,两天里陪父母烧锅,教他们使用红米手机,聊天,吃饭。家里很好࿰
1 简介

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

2 重构原则

使用XMind总结本章的主要内容,在各个小节可以看到如下的内容:
在这里插入图片描述
大体内容如上。

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 rentalresult += "\t" + rental.getMovie().getTitle() + "\t"+ String.valueOf(rental.getCharge()) + "\n";totalAmount += rental.getCharge();}// add footer linesresult += "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 rentalresult += "\t" + each.getMovie().getTitle() + "\t"+ String.valueOf(each.getCharge()) + "\n";}// add footer linesresult += "Amount owed is " + String.valueOf(getTotalCharge()) + "\n";result += "You earned " + String.valueOf(getTotalFrequentRenterPoints())+ " frequent renter points";return result;}

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

// 译注:此即所谓query methodprivate 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整合
《重构 改善既有代码的设计》之代码的坏味道
《重构 改善既有代码的设计》之重构列表


推荐阅读
  • 开发笔记:里氏替换原则
    本文由编程笔记#小编为大家整理,主要介绍了里氏替换原则相关的知识,希望对你有一定的参考价值。1.定义:如果对每一个类型为T1的对象o1,都有类型为T2的对象o2, ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Androidwifi对象属性及简易Demo本章介绍Android开发中WiFi热点和WiFi属性的获取,介绍WiFi的名称、状态等属性以及获取周围 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 本文详细介绍了GetModuleFileName函数的用法,该函数可以用于获取当前模块所在的路径,方便进行文件操作和读取配置信息。文章通过示例代码和详细的解释,帮助读者理解和使用该函数。同时,还提供了相关的API函数声明和说明。 ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
author-avatar
书友48058773
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有