很好,我们终于迈出了重构的第一步,而这第一步我们瞄准了代码问题的重灾区——超级大函数。超级大函数之所以是代码问题的重灾区,就是因为它们往往难于阅读、难于维护。面对大函数我们采取的办法是拆分,以功能为核心将其拆分成一个一个独立的函数。拆分后的程序变得易于阅读了,因为要读懂程序你不再需要读完所有代码,选择性的读取那些顶级函数,只需了了数行代码,你就可以明白整个程序。
但是,当我们将数千行的大函数分解成数十个小函数时,另一个问题出现了。想象一下,数十个函数被杂乱无章地堆放在一个对象中,看看就让人头疼。实际上,我们是不会这样做的。当我们开始了对大函数的分解时,随之而来的就是对大对象的分解。大对象,就是指的那些包含数十个甚至上百个方法或者函数,功能无所不包的超级对象。在很多遗留系统中,总有那么几个超级对象,系统几乎所有的功能都在它的里面有对应方法。这样的对象,密密麻麻的方法让人困惑,更关键的是,各种各样的功能被耦合在一起,稍有修改就会影响到许多功能,甚至让那些毫不相干的功能产生BUG。因此,我们应当合理地拆分我们的大对象。
与大函数一样,很多时候遗留系统中的大对象,也都是伴随系统业务复杂度的逐渐增长而出现的,我们来看看它的演进过程吧。我们说软件实际上是对现实世界的模拟,通过这种模拟,实现信息化的管理,来提高我们的生产效率。但是,现实世界是复杂的,各种事物之间存在着各种各样纷繁复杂的联系,因此我们不可能完全模拟现实世界的所有,只可能是现实世界的一部分,客户急需要模拟的那一部分。
人的大脑认识事物总是一个由简单到复杂的过程,这是我们的客观规律。因此,我们的软件模拟真实世界也是一个由简单到复杂的过程。最开初我们的想法总是非常简单而单纯的,就是让软件做一件非常简单而明确的事情。由于这时候业务非常简单,我们不需要太多的类和方法就可以实现业务操作。比如开票业务,就是将已开具的发票信息读取出来,保存。这样一个简单操作,设计成一个简单的开票业务类合情合理。
但是,随着软件模拟真实世界的不断发展,业务变得越来越复杂。比如这个开票业务,我们随后的业务开始变更,要检查购方是否存在、开票人是否有权限、库存中是否还有发票,等等。起初只有一种开票方式,但随着非正常开票业务的增加,许多相关的业务也随之变化……随着业务的不断增加,软件代码的规模也在发生着质的变化(如图6.1所示)。
图6.1 开票业务的演化过程
过去开票业务类只有百来行代码,现在被膨胀到数千行代码。各种条件语句层层嵌套,各种临时变量穿插跑位,程序变得难于理解。由于读不懂代码,修改代码的程序员开始在走钢丝,一不小心改动了某个关键程序就可能引入重大BUG。为了避免重大BUG的出现,测试人员耗费巨大精力进行严格的测试。毫无疑问,软件开始进入一种恶性循环,软件退化开始一步步加深。
面对这种软件规模增大而带来的恶性循环,我们必须做出改变。面对问题我们不能病急乱投医,而是应当对症下药。这个正确的药方就是以职责驱动设计思想为核心,调整我们的程序结构,构建高内聚、低耦合的软件系统。职责驱动设计,就是要求我们设计的所有类和接口,都要有自己的职责定义。而每个类和接口内部的所有方法和属性都是围绕着该职责来进行的,它们都是高度相关的。每个类和接口决不去做跟自己职责无关的事情,所有与自己职责无关的事情,都应当交给其它拥有该职责的类来完成,而自己仅仅是去调用。这就是职责驱动设计的思想,而每个类其内部包含的功能所达到的高度相关的程度,我们称之为“内聚”。
概念似乎有一些抽象,我们来举例说明吧。对于开票业务,我们设计了开票业务类来处理它,因此开票业务类的职责就是完成开票操作,这似乎毫无问题。但是,我们仔细审视开票操作,就会发现它包含了好几个部分:首先,我们读取客户、开票人、发票库存等信息进行相关的校验,然后保存这些发票到数据库中,最后统计当月的票量及金额。通过这样的分析,它们似乎不再那么功能相关了,读取和校验客户、开票人、发票库存等信息是客户、开票人、发票库存实体类的职责,读取和保存发票似乎是发票类的职责,而统计当月票量与金额似乎是财会统计类的职责。分与不分,完全取决于软件代码的复杂程度。如果总共也就几十行代码,我们写成一个类中的几个方法就可以了;但随着功能复杂度的加深,那么我们必须得拆分,分配到不同的类中配合完成我们的功能。
随着软件业务的不断变化,我们的软件在发生着质的变化。发票保存前我们必须要进行一系列的校验工作:检查购方是否存在、开票人是否有权限、是否还有发票库存,等等。不同的校验,读取的是不同的数据,它们的顺序可能变化,校验的个数也可能在调整。随着需求的变化,一些校验被增加进来而另一些则被剔除。我们判断功能是否相关的一个非常重要的原则,就是是否是软件变更的同一个原因。比如,“检查购方是否存在”与“开票人是否有权限”,不是软件变更的同一个原因:“检查购方是否存在”是与客户信息管理直接相关,而“开票人是否有权限”则是与用户权限定义密切相关,因此它们不能放在同一个类中。为什么呢?因为“检查购方是否存在”的业务逻辑变更时,不应当影响到“检查开票人是否有权限”的功能。最好的办法就是,将它们各自封装在各种相关的业务类中(如图6.2所示)。
图6.2 开票业务的拆分
经过以上分析我们发现,开票操作随着业务逻辑的不断发展,应当在原有的程序结构上,将开票业务类拆分成几个部分:各种校验类、发票业务类与财会统计类。这样的拆分使得开票业务类最终由一个什么都干的多面手,变成了一个管理者。它不再参与那些具体的工作,而是将工作分配给不同的人,成为一个组织协调者。经过这样的调整,我们的程序将变得更加易于阅读、维护、变更。
大话重构连载首页:
http://fangang.iteye.com/blog/2081995
特别说明:希望网友们在转载本文时,应当注明作者或出处,以示对作者的尊重,谢谢!
- 大小: 23.8 KB
- 大小: 25.5 KB
分享到:
相关推荐
Android之大话设计模式——:抽象工厂模式借鉴.pdf
大话Oracle RAC:集群、高可用性、备份与恢复(带目录清晰中文完整版)
大话Oracle RAC:集群、高可用性、备份与恢复。 此书被认为不可多得的好资料之一:大话Oracle RAC(PDF经典),看完之后深有感触,发出来共享一下。
Android之大话设计模式——:抽象工厂模式参考.pdf
初中语文文摘历史“大话王”郭台铭:被夏普狠狠摔了个大跟
《大话Oracle.RAC:集群、高可用性、备份与恢复(第2版)》是一部深入探讨Oracle数据库Real Application Clusters(RAC)技术的专业书籍,主要围绕Oracle RAC的集群架构、高可用性策略以及数据库的备份与恢复策略...
《大话数据分析:Tableau数据可视化实战》的数据集是一份重要的资源,对于想要学习和提升Tableau数据可视化技能的人来说极具价值。Tableau是一款强大的商业智能工具,它允许用户通过直观的拖放界面来探索和可视化...
《大话Oracle RAC:集群 高可用性 备份与恢复》可以作为数据库开发人员、数据库管理员、数据库初学者及其他数据库从业人员的工作参考手册,也可以作为大中专院校相关专业师生的参考用书和相关培训机构的培训教材。
《大话存储:存储系统底层架构原理极限剖析(终极版)》是一本深入探讨存储技术的专业书籍,由一位对技术充满热情的作者精心撰写。这本书以其严谨的态度和丰富的想象力,揭示了存储系统的底层奥秘,旨在帮助读者全面...
目前国内阐述网络存储的书籍少之又少,大部分是国外作品,对存储系统底层细节的描述不够深入,加之术语太多,初学者很难真正理解网络存储的精髓。《大话存储2:存储系统架构与底层原理极限剖析》以特立独行的行文风格...
大话Java:从零基础到数据库、Web开发以漫画的形式,由浅入深、循序渐进地介绍Java编程的常用技术和方法,内容涵盖了Java基本语法结构、面向对象特征、集合框架体系、异常处理、GUI编程、MySQL数据库、JDBC数据库...
大话存储:存储系统底层架构原理极限剖析(终极版)第3部分 大话存储:存储系统底层架构原理极限剖析(终极版)第3部分大话存储:存储系统底层架构原理极限剖析(终极版)第3部分
《大话移动APP测试》是一本详尽介绍Android与iOS平台测试应用的指南,旨在帮助读者深入理解并掌握移动应用的测试技术。本书全面覆盖了移动端的测试领域,包括平台特性、设备兼容性、功能测试、性能测试、安全测试等...
大话存储:存储系统底层架构原理极限剖析(终极版)_张冬2015.01_P989
大话移动APP测试 Android与iOS应用测试指南
(JAVA)大话类、方法、参数、对象、属性以及面向对象的开发模式.pdf
《大话3WDF解包器:深入解析与应用》 在计算机游戏中,资源的管理与存储是一项重要的技术,尤其对于大型多人在线游戏(MMORPG)如“大话西游”系列来说,如何高效地组织和加载游戏资源是至关重要的。本文将详细探讨...
在《大话处理器》一书中,作者万木杨带领我们走进了处理器的奇妙世界。 首章“漫游计算机世界”,作者通过生动的类比和丰富的图片,向我们揭示了计算机的前世今生,以及它们的内部构造。从早期的机械式计算机,到...