重构 改善既有代码的设计——重构原则

1.何谓重构?

答:

A.重构(名词意义):对软件内部结构的调整,目的是在不改变软件可观察行为的前提下,提高其理解性,降低其修改成本;

B.重构(动词意义):使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构;

总结:为了更容易理解和修改软件,在不改变软件功能的前提下,调整软件结构;


重构的两种思维:在软件开发的过程中,编码和重构经常会交叉,因为二者是两种不同思维方式,为避免产生思维混乱,最好将二者独立开来:同一时间只做同一件事,要么编程,不做重构;要么重构,不做编程;

评:编程考虑的是实现功能,为此常常可能牺牲结构、性能、扩展性,着眼的是局部等,这都是难免的;重构考虑的是重新梳理软件的功能之间的逻辑和功能内部的实现,着重的是系统,所以更多的是考虑理解性、扩展性、稳定性等;如果二者同时进行的话,可能就会产生考虑过多,导致无法编码或编码艰难;本质上,编码和重构是存在矛盾的,结合我以往的经历来看,同时做两件相互冲突的事,就会丧失思考力,因为你考虑的东西太多,结果反而不知如何是好了!


总评:把软件比作人体,重构就是锻炼身体,可以排除体内的负能量(垃圾、毒素等),也可以提升自身的身体素质,增加器官的活性,提升身体的抵抗力; 你可以去健身房,也可以抽个业余时间;锻炼的目的一般来说有两个:1.改变个人的精神状态,使得身体处于积极状态;2.为了追求身体之美,像古希腊人一样为了追求身体之美而锻炼;


2.为何重构?

A.改进软件设计:软件的设计随着时间的流逝,会逐渐的腐败。当程序员修改和添加功能的时候,着重的是功能的实现。所以无法统揽全局,从系统的角度来考虑修改或添加的模块对整体的影响;所以我们需要重构,来帮助我们不断矫正软件,使之稳定运行;

评:犹如人体之五脏六腑,各官其能,经由血管脉络连贯全身,使人能正常生存并思考;人体的结构是进化的结果,进化总是倾向完美性或适合性的;计算机就是软件的生活环境,如果软件的结构很糟糕,那么软件也是运行的很不开心的。重构就相当于使得软件的结构更加符合计算机的要求;归根到底,在我看来,计算机的结构本身就是人利用思维创造的合理性的实体,也是人的思维的体现;软件也是思维的产品;我们要做的就是让一件产品运行到另外一件产品中;


B.让软件更易理解:软件的运行是在计算机中进行的,但是软件的开发往往是多人开发集成的;所以我们在追求计算机的理解的同时,也要让别人理解。后者往往要比前者花费的时间更长,更影响软件的运行;

评:“幸福家庭家家相似,不幸的家庭各各不同”,合理性对于所有人来说是相同的;所以合理性也是衡量软件质量的一个标准(自我理解),所以,如果别的程序员看不懂我们的软件的时候,在怀疑他人的能里的同时也应该考虑自己的设计是否真的合理;就像1+1 = 2,你可以不喜欢,但是只要你能理解对软件来说就是成功的;


C.提高编程速度:对系统的理解时间要大于编程时间,如果对整个系统胸有成竹,接下来只是写代码的功夫了;

评:语言都是一种世界观,java的面向对象、C的面向过程本质上都是一种对世界的理解;慢慢的就会发现,所谓程序只是用来实现功能,真正困难的还是人对事物的理解和认识;就像王国维的人生三境“看山是山,看水是水”、“看山不是山,看水不是水”、看山还是山,看水还是水“。重构考究的就是程序员的思维境界,看水还是看水全看个人能力;境界高,看待事物的方式不同,解决起来也是容易的很;境界低,只能不断摸索,最后还是执于一隅;

D.重构找到bug:重构就是让软件系统重归合理性之旅,必须梳理清楚软件系统的逻辑,在复归合理性的过程中,我们会逐渐的发现不合理之处(bug)。


总评:为何重构犹如问人为何锻炼身体一样。改进软件设计和重构找到bug,相当于人通过锻炼修复身体的损伤,保证了人的正常功能;让软件更易理解和提高编程速度就相当于改善个人的状态,使得充满激情和正能量;我的感受是一般运动后都会很放松,也更健谈,做事的效率也会提升很多;


3.何时重构?

答:软件程序无非是增删改查,添加和去除功能的时候要重构,一方面是为了下次能更好的理解增加的功能模块,其次也是为了在开发的过程中逐渐的把代码结构理清,便于接下来的开发;修改功能时要重构,调试过程中重构,让代码更具可读性,设想如果程序出错,而我又无法准确定位原因的时候,充分反应了代码不够清晰,无法锁定异常所在;查即代码复查,代码复查类似于”结对编程“,让别人理解你的程序,一方面突破自己的固有思维模式,同时也是判断软件的可读性的一种方式;


4.何时不该重构?

答:

A.现有代码过于混乱,重构的成本大于重写

B.代码在大部分情况下无法正常运行,稍作改动,就报很多错误,无法稳定运作;

C.项目临近交付的时候;


5.重构的难题

A.数据库:数据库重构的难题有二:1.商用软件的数据库和业务关联;2.数据的迁移;

B.修改接口:面向对象的封装性使得程序员可以将功能实现和接口独立开来,接口一旦发布,就很难修改。所以如果功能扩展而旧接口无法满足需求时,一个不坏的方法就是在旧接口中调用新的接口;其次,务必注意,接口发布之先,一定要修改代码所有权政策;

C.难以通过重构手法完成的设计改动:有些项目过大,通过重构完全无法修改程序的设计


6.设计与重构

A.只有设计:结合我自身的项目经历来看,由于初始用户需求不是太明确,项目又略显复杂。所以在开发之初总是想着考虑各种情况,尽量的让软件设计保持灵活;但是最后却发现,在开发的过程中总是会遇到各种问题,这个时候只能是修改设计,开发到最后设计也面目全非了,开发过程中也很累;

B.只有重构:只有重构而不考虑开前的设计倒也可以,一个问题是如果不能熟练的掌握重构,要想在开发过程中很好的重构程序几乎是不可能的;毕竟设计更着重与系统的流程和架构,受业务影响,重构更关注的是功能模块的实现逻辑和模块之间的关系,更偏重技术角度;

C.设计+重构:这种方式会好很多,一方面可以简化设计,同时简化的设计又可以很好的指导开发,在开发的过程中遇到问题也可以通过重构灵活的修改设计;也就是说我们掌握重构后有足够的信心应对需求的变化。


7.重构与性能

  重构不一定提升软件性能,但可以使性能提升更容易;性能提升一般有三种方式:

  A.时间预算法:预先定义软件各功能模块的时间成本,严格控制,从而提升系统运行时间;对于一般软件来说,无需这种要求;

  B.持续关注法:程序员在做任何修改时,必须保证程序的高性能;一般很难实现,因为任何一次的修改如果是为了性能提升的话,通常都会使程序难以维护;如果以此换来程        序的性能提升倒也值得,但是大部分情况下并非如此;性能改善往往着于一角,局部的性能提升了,但是整体的性能却是无法保证;不过就我开发的经历来说,部分性能的        提  升在很大程度上会提升系统性能,当然前提是软件编码很糟糕,有很大的优化空间;

  C.根据二八原则,影响程序80%性能的往往是20%的代码;所以初始编码的时候无需耗费过多精力于重构,待编码完成,就集中精力测试,找到影响性能的20%代码,然后采用持续关注法和时间预算法(我认为两种方式可以交叉使用),集中优化;


8.重构源于何处?

你猜!大笑




第1章 重构,第一个案例 1 1.1 起点 1 1.2 重构的第一步 7 1.3 分解并重组statement() 8 1.4 运用多态取代与价格相关的条件逻辑 34 1.5 结语 52 第2章 重构原则 53 2.1 何谓重构 53 2.2 为何重构 55 2.3 何时重构 57 2.4 怎么对经理说 60 2.5 重构的难题 62 2.6 重构设计 66 2.7 重构与性能 69 2.8 重构起源何处 71 第3章 代码的坏味道 75 3.1 Duplicated Code(重复代码) 76 3.2 Long Method(过长函数) 76 3.3 Large Class(过大的类) 78 3.4 Long Parameter List(过长参数列) 78 3.5 Divergent Change(发散式变化) 79 3.6 Shotgun Surgery(霰弹式修改) 80 3.7 Feature Envy(依恋情结) 80 3.8 Data Clumps(数据泥团) 81 3.9 Primitive Obsession(基本类型偏执) 81 3.10 Switch Statements(switch惊悚现身) 82 3.11 Parallel InheritanceHierarchies(平行继承体系) 83 3.12 Lazy Class(冗赘类) 83 3.13 Speculative Generality(夸夸其谈未来性) 83 3.14 Temporary Field(令人迷惑的暂时字段) 84 3.15 Message Chains(过度耦合的消息链) 84 3.16 Middle Man(中间人) 85 3.17 Inappropriate Intimacy(狎昵关系) 85 3.18 Alternative Classes with Different Interfaces(异曲同工的类) 85 3.19 Incomplete Library Class(不完美的库类) 86 3.20 Data Class(纯稚的数据类) 86 3.21 Refused Bequest(被拒绝的遗赠) 87 3.22 Comments(过多的注释) 87 第4章 构筑测试体系 89 4.1 自测试代码的价值 89 4.2 JUnit测试框架 91 4.3 添加更多测试 97 第5章 重构列表 103 5.1 重构的记录格式 103 5.2 寻找引用点 105 5.3 这些重构手法有多成熟 106 第6章 重新组织函数 109 6.1 Extract Method(提炼函数) 110 6.2 Inline Method(内联函数) 117 6.3 Inline Temp(内联临时变量) 119 6.4 Replace Temp with Query(以查询取代临时变量) 120 6.5 Introduce Explaining Variable(引入解释性变量) 124 6.6 Split Temporary Variable(分解临时变量) 128 6.7 Remove Assignments to Parameters(移除对参数的赋值) 131 6.8 Replace Method with Method Object(以函数对象取代函数) 135 6.9 Substitute Algorithm(替换算法) 139 第7章 在对象之间搬移特性 141 7.1 Move Method(搬移函数) 142 7.2 Move Field(搬移字段) 146 7.3 Extract Class(提炼类) 149 7.4 Inline Class(将类内联化) 154 7.5 Hide Delegate(隐藏“委托关系”) 157 7.6 Remove Middle Man(移除中间人) 160 7.7 Introduce Foreign Method(引入外加函数) 162 7.8 Introduce Local Extension(引入本地扩展) 164 第8章 重新组织数据 169 8.1 Self Encapsulate Field(自封装字段) 171 8.2 Replace Data Value with Object(以对象取代数据值) 175 8.3 Change Value to Reference(将值对象改为引用对象) 179 8.4 Change Reference to Value(将引用对象改为值对象) 183 8.5 Replace Array with Object(以对象取代数组) 186 8.6 Duplicate Observed Data(复制“被监视数据”) 189 8.7 Change Unidirectional Association to Bidirectional(将单向关联改为双向关联) 197 8.8 Change Bidirectional Association to Unidirectional(将双向关联改为单向关联) 200 8.9 Replace Magic Number with Symbolic Constant(以字面常量取代魔法数) 204 8.10 Encapsulate Field(封装字段) 206 8.11 Encapsulate Collection(封装集合) 208 8.12 Replace Record with Data Class(以数据类取代记录) 217 8.13 Replace Type Code with Class(以类取代类型码) 218 8.14 Replace Type Code with Subclasses(以子类取代类型码) 223 8.15 Replace Type Code with State/Strategy(以State/Strategy取代类型码) 227 8.16 Replace Subclass with Fields(以字段取代子类) 232 第9章 简化条件表达式 237 9.1 Decompose Conditional(分解条件表达式) 238 9.2 Consolidate Conditional Expression(合并条件表达式) 240 9.3 Consolidate Duplicate Conditional Fragments(合并重复的条件片段) 243 9.4 Remove Control Flag(移除控制标记) 245 9.5 Replace Nested Conditional with Guard Clauses(以卫语句取代嵌套条件表达式) 250 9.6 Replace Conditional with Polymorphism(以多态取代条件表达式) 255 9.7 Introduce Null Object(引入Null对象) 260 9.8 Introduce Assertion(引入断言) 267 第10章 简化函数调用 271 10.1 Rename Method(函数改名) 273 10.2 Add Parameter(添加参数) 275 10.3 Remove Parameter(移除参数) 277 10.4 Separate Query from Modifier(将查询函数和修改函数分离) 279 10.5 Parameterize Method(令函数携带参数) 283 10.6 Replace Parameter with Explicit Methods(以明确函数取代参数) 285 10.7 Preserve Whole Object(保持对象完整) 288 10.8 Replace Parameter with Methods(以函数取代参数) 292 10.9 Introduce Parameter Object(引入参数对象) 295 10.10 Remove Setting Method(移除设值函数) 300 10.11 Hide Method(隐藏函数) 303 10.12 Replace Constructor with Factory Method(以工厂函数取代构造函数) 304 10.13 Encapsulate Downcast(封装向下转型) 308 10.14 Replace Error Code with Exception(以异常取代错误码) 310 10.15 Replace Exception with Test(以测试取代异常) 315 第11章 处理概括关系 319 11.1 Pull Up Field(字段上移) 320 11.2 Pull Up Method(函数上移) 322 11.3 Pull Up Constructor Body(构造函数本体上移) 325 11.4 Push Down Method(函数下移) 328 11.5 Push Down Field(字段下移) 329 11.6 Extract Subclass(提炼子类) 330 11.7 Extract Superclass(提炼超类) 336 11.8 Extract Interface(提炼接口) 341 11.9 Collapse Hierarchy(折叠继承体系) 344 11.10 Form Tem Plate Method(塑造模板函数) 345 11.11 Replace Inheritance with Delegation(以委托取代继承) 352 11.12 Replace Delegation with Inheritance(以继承取代委托) 355 第12章 大型重构 359 12.1 Tease Apart Inheritance(梳理并分解继承体系) 362 12.2 Convert Procedural Design to Objects(将过程化设计转化为对象设计) 368 12.3 Separate Domain from Presentation(将领域和表述/显示分离) 370 12.4 Extract Hierarchy(提炼继承体系) 375 第13章 重构,复用与现实 379 13.1 现实的检验 380 13.2 为什么开发者不愿意重构他们的程序 381 13.3 再论现实的检验 394 13.4 重构的资源和参考资料 394 13.5 从重构联想到软件复用和技术传播 395 13.6 小结 397 13.7 参考文献 397 第14章 重构工具 401 14.1 使用工具进行重构 401 14.2 重构工具的技术标准 403 14.3 重构工具的实用标准 405 14.4 小结 407 第15章 总结 409
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值