重构是项目作到 必定程度后必然要作的事情。代码重构,能够改善既有的代码设计,加强既有工程的可扩充、可维护性。随着项目需求的不断迭代,需求的不断更新,咱们在项目中 所写的代码也在时时刻刻的在变化之中。在一次新的需求中,你添加了某些功能模块,但这些功能模块有可能在下一次需求中不在适用。或者你由于需求迭代与变 更,使你原有的方法或者类变得臃肿,以及各个模块或者层次之间耦合度增长。此时,你要考虑重构了。html
重构,在《重构,改善既有代码的设计》这本经典的书中给出了定义,大概就是:在不改变代码对外的表现的状况下,修改代码的内部特征。说白了,就是咱们的测试用例不变,而后咱们对既有的代码的结构进行修改。重构在软件开发中是常常遇到的,也是很是重要的。在需求迭代,Debug,Code Review时,你均可以对你既有的代码进行重构。编程
在接下来的几篇博文中,我想与你们一块去窥探一下代码重构的美丽,学习一下代码重构的一些规则。固然在每一个规则中都有小的Demo, 在本篇博客以及相关内容的博客是使用Swift语言实现的。固然,和设计模式相同,重构重要的是手法和思想,和使用什么样的语言关系不大。经典的重构书籍中是使用Java语言来实现的,若是你对PHP, Python等其余语言比较熟悉,彻底可使用这些语言来测试一些重构手法。设计模式
本篇博客的主题就是经过一些列的重构手法,对既有的须要重构的函数或者方法进行重 构。而且会将每一个示例在GitHub上进行分享,感兴趣的小伙伴能够对其进行下载。有的小伙伴说了,我没有Mac,怎么对你写的Swift代码进行编译 呢?这个问题好解决,你能够看我以前发表的这篇博客《窥探Swift之使用Web浏览器编译Swift代码以及Swift中的泛型》。你能够将相关代码进行拷贝,在浏览器中观察结果。由于在线编译的网站是国外的,访问起来也许会有一些卡顿,不过是能够用的。好前面扯了这么多了,进入今天的主题。浏览器
目录:函数
1、将大函数按模块拆分红几个小的函数post
2、将微不足道的小函数经过inline进行整合单元测试
3、将一些临时变量使用函数替换(以函数查询替代临时变量)学习
4、将复杂表达式拆分红多个表达式(以多个解释性临时变量拆分复杂表达式)测试
5、将在不一样语义下具备不一样含义的临时行变量进行拆分网站
6、移除对函数参数的赋值(引入另外一个临时性变量)
7、以对象取代函数
1、Extract Method(提取函数)-------将大函数按模块拆分红几个小的函数
Extract Method被翻 译成中文就是提取函数的意思,这一点在代码重构中用的很是很是的多。在重构时提倡将代码模块进行细分,由于模块越小,可重用度就越大。不要写大函数,若是 你的函数过大,那么这意味着你的函数须要重构了。由于函数过大,可维护性,可理解性就会变差。而且当你实现相似功能的时候就容易产生重复代码。写代码时, 最忌讳的就是代码重复。这也就是常常所说的DRY(Don`t Repeat Yourself)原则。因此当函数过长时,你须要将其细分,将原函数拆分红几个函数。
下 方将会经过一个示例来直观的感觉一下Extract Method,固然这些示例不是我原创的,是《重构:改善既有代码的设计》中Java示例演变的Swift版,在写Swift代码时,对原有的示例进行了 一些修改,算是伪原创吧。不过目的只有一个:但愿与你们交流分享。实在是没有必要再找其余的例子说明这些重构规则,由于《重构:改善既有的代码的设计》这 本书真的是太经典了。
1.须要重构的代码以下所示。下方代码中的MyCustomer类中有两个常量属性,而且该类提供了一个构造器。该类还提供了一个输出方法,就是第一该类中的属性进行打印说明,其实该类中没有什么功能。
在写好须要重构的类后,咱们要为该类写一个测试用例。这便于在咱们重构时对重构的 正确性进行验证,由于每次重构后都要去执行该测试用例,以保证咱们重构是正确的。下方截图就是为上方示例写的测试用例以及该测试用例的打印结果。固然重构 后咱们也须要调用该测试用例,并观察打印结果是否与以前的一致。固然若是你不想本身观察,你能够为上面的类添加相应的单元测试,这也是在常规项目中常常使 用的。至于若是添加测试用例,咱们会在后面的博客中进行详细介绍。下方就是上述类的测试用例和输出结果:
2.接下来咱们对上面类中的printOwning函数进行分析。上述类能够正常 工做,这是确定的。可是printOwning()函数写的不够好。由于它干了太多的事情,也就是说该函数包括了其余子模块,须要对其进行拆分。由上面截 图中的红框能够看出,每一个红框就表明着一个独立的功能模块,就说明这一块代码能够被拆分红独立的函数。在拆分子函数时,咱们要为该函数起一个与改代码块功 能相符合的名字。也就是说当你看到该函数名字时,你就应该知道该函数是干吗的。
下方代码段就是咱们重构后的类。说白的,就是对函数中能够进行独立的模块进行提 取,并为提取的新的函数命一个合适的名称。通过重构后printOwing()函数就只有两行代码,这样看其中调用的函数名也是很容易理解其做用的。下方 拆分出来的三个函数也是一个独立的模块,由于函数短小,因此易于理解,同时也易于重用。通过Extract Method,固然好处是多多的。通过重构后的代码,我在调用上述的测试用例,输出结果和原代码是一直的,若是不一致的话,那么说明你的重构有问题呢,需 要你进行Debug。
二. Inline Method ---- 内联函数:将微不足道的小函数进行整合
看过《周易》的小伙伴应该都知道,《周易》所表达的思想有一点就是“物极必反”。 《周易》中的六十四卦中的每一卦的“上九”(第六位的阳爻)或者“上六”(第六位的阴爻)都是物极必反的表现。其实《周易》其实就是计算机科学中二进制的 表象,由于太极生两仪(2进制中的2),两仪生四象(2的平方为4),四象生八卦(4 x 2 = 8),八卦有演变出六十四卦。六十四卦的就是2进制中的0-1排列。九五至尊,九六就物极必反了。wo kao, 扯远了,言归正传,固然这提到《周易》不是说利用周易如何去算卦,如何去预测,本宝宝不信这东西。不过《周易》中的哲学仍是颇有必要学习一下的。有所取, 有所不取。
回到本博客的主题,Inline Method实际上是和Extract Method相对的。当你在重构或者平时编程时,对模块进行了过分的封装,也就是使用Extract Method有点过头了,把过于简单的东西进行了封装,好比一个简单的布尔表达式,并且该表达式只被用过一次。此时就是过分的使用Extract Method的表现了。物极必反,因此咱们须要使用Inline Method进行中和,将过分封装的函数在放回去,或者将那些没有必要封装的函数放回去。也就是Extract Method相反的作法。
至于Inline Method规则的示例呢,在此就不作过多的赘述了,由于只须要你将Extract Method的示例进行翻转便可。
三.Replace Temp with Query----以查询取代临时变量: 将一些临时变量使用函数替代
1.Replace Temp with Query说白了就是将那些有着复杂表达式赋值而且屡次使用的临时变量使用查询函数取代,也就是说该临时变量的值是经过函数的返回值来获取的。这样一来在 实现相似功能的函数时,这些复杂的临时变量就能够进行复用,从而减小代码的重复率。下方就是Replace Temp with Query规则的一个特定Demo,接下来咱们要对getPrice()函数使用Replace Temp with Query规则进行重构。
对上面的小的demo建立对应的测试用例是少不了的,由于咱们要根据测试用例还测试我重构后的代码是否一致,下方截图就是该代码的测试用例以及输出结果,具体以下所示。
2.接下来就是对Procut类中的getPrice()函数进行分析并重构了。在getPrice()函数中的第一个红框中有一个 basePrice临时常量,该常量有一个较为复杂的赋值表达式,咱们能够对其使用Replace Temp with Query进行重构,可就是建立一个函数来返回该表达式的值。第二个红框中的discountFactor临时变量被屡次使用,咱们能够对其经过 Replace Temp with Query规则进行重构,具体重构后的代码以下所示。
由重构后的代码容易看出,上面咱们提到的临时常量或者变量都不存在了,取而代之的是两个查询方法,对应的查询方法返回的就是以前消除的临时变量或常量的值。
4、Inline Temp ---内联临时变量:与上面的Replace Temp with Query相反
当临时变量只被一个简单的表达式赋值,而该临时变量妨碍了其余重构手法。此时咱们就不该 该使用Replace Temp with Query。之因此有时咱们会使用到Inline Temp规则,是由于Replace Temp with Query规则使用过分形成的状况,仍是物极必反,使用Replace Temp with Query过分时,就须要使用Inline Temp进行修正,固然Inline Temp的示例与Replace Temp with Query正好相反,在此就不作过多的赘述了。
5、Introduce Explaining Variable---引入解释性变量:将复杂的表达式拆分红多个变量
当一个函数中有一个比较复杂的表达式时,咱们能够将 表达式根据功能拆分红不一样的变量。拆分后的表达式要比以前未拆分的表达式的可读性更高。将表达式拆分红相应的临时变量,也就是Introduce Explaining Variable,若是临时变量被屡次使用的话,咱们还能够尝试着使用Replace Temp with Query规则去除临时变量,也就是将临时变量换成查询函数。
1.在下方Product类中的getPrice()方法中返回了一个比较长的表达式,第一眼看这个函数感受会很是的不舒服。由于它返回的表达式太长了,并且可读性不太好。在这种状况下就颇有必要将该表达式进行拆分。
2.接下来就可使用Introduce Explaining Variable规则,引入解释性变量。顾名思义,咱们引入的变量是为了解释该表达式中的一部分的功能的,目的在于让该表达式具备更好的可读性。使用 Introduce Explaining Variable规则,就至关于为该表达式添加上相应的注释。下方截图就是使用 Introduce Explaining Variable规则进行重构后的结果。
3.引入临时变量是为了更好的可读性,若是临时变量所表明的表达式屡次使用,咱们就能够对上述函数在此使用Replace Temp with Query规则进行重构。也就是去除常用并且表达式比较复杂的临时变量,下方代码段是对上述函数进行Replace Temp with Query重构,去掉临时变量,再次重构后的结果以下所示。
6、Split Temporary Variable-----分解临时变量:一心不可二用
什么叫分解临时变量的,具体说来就是在一个函数中一个临时变量不能作两种事 情,也就是一个临时变量不能赋上不一样意义的值。若是你这么作了,那么对不起,请对该重复使用的临时变量进行分解,也就是说你须要建立一个新的临时变量来接 收第二次分配给第一个临时变量的值,并为第二个临时变量命一个确切的名字。
下方第一个函数是重构前的,能够看出temp被重复的赋值了两次的值,若是 这两个值关系不大,并且temp不足以对两个值的意思进行说明。那么就说明该段代码就应该被重构了。固然,重构的作法也是很是简单的,只须要术业有专攻即 可,各司其职,而且为每一个临时变量命一个合适的名字便可。具体作法以下所示。
7、Remove Assignments to Parameters----移除对参数的赋值
“移除对参数的赋值”是什么意思呢?顾名思义,就是在函数中不要对函数参数 进行赋值。也就是说你在函数的做用域中不要对函数的参数进行赋值(固然,输入输出参数除外),当直接对函数的参数进行修改时,对不起,此时你应该对此重 构。由于这样会是参数的原始值丢失,咱们须要引入临时变量,而后对这个临时变量进行操做。
1.下方这个discount()函数就作的很差,由于在 discount()函数中直接对非inout参数inputVal进行了修改而且返回了,咱们不建议这样作。遇到这种状况,咱们须要使用Remove Assignments to Parameters规则对下方的函数进行重构。
2.固然重构的手法也特别简单,就是须要将上面的inputVal使用函数的临时变量进行替代便可,下方就是重构后的函数。
八.Replace Method with Method Object----以函数对象取代函数
当一个特别长的函数,并且函数中含有比较复杂的临时变量,使用上述那些方法 很差进行重构时,咱们就要考虑将该函数封装成一个类了。这个对应的类的对象就是函数对象。咱们能够将该场函数中的参数以及临时变量转变成类的属性,函数要 作的事情做为类的方法。将函数转变成函数类后,咱们就可使用上述的某些方法对新的类中的函数进行重构了。具体作法请看下方示例。
1.下方示例中的discount函数有过多的参数(固然,现实项目工程中参数比这个还要多),并函数中含有多个临时变量,假设函数功能比较复杂,并且比较长。下方示例对该函数使用上述那些规则进行重构会比较复杂,此时咱们就能够将该函数抽象成一个类。
2.重构的第一步就是将上述discount()函数抽象成Discount类。在Discount类中有六个属性,这六个属性分别对应着 discount()函数的不一样参数。除了添加参数属性外,咱们在函数类提取时还添加了一个Account的委托代理对象。该委托代理对象是为了在 Discount类中访问Account类中依赖的数据,下方是第一次重构后的代码。
3.接着,咱们就能够在新的Discount类中的compute()方法中使用 咱们上述介绍的规则进行重构。对compute()方法进行分析,咱们发现importandValue等属性是能够经过Replace Temp with Qurey 规则进行消除的。所为咱们能够再次对上述方法进行重构,重构后的具体代码以下:
今天的博客主要讲了如何对既有代码中的函数进行重构,在本篇博客中提到了8大规 则。这8大规则在函数代码重构时时很是实用的,而且也是很是重要的。仍是那句话,虽然代码是使用Swift语言实现的,可是代码重构的手法和思想和语言无 关。接下来还会继续更新关于代码重构的博客,敬请期待吧。