代码重构(五):继承关系重构规则

陆陆续续的发表了多篇关于重构的文章了,仍是那句话,重构是一个项目迭代开发中必不可少的一个阶段。其实重构伴随着你的项目的整个阶段。在前几篇关于重构的文章中咱们谈到了函数的重构、类的重构、数据的重构以及条件表达式的重构,那么今天我们就来聊聊继承关系的重构。固然仍是延续前几篇博客的风格,咱们在博客中的代码实例依然使用Swift语言来实现,固然仍是那句话,使用什么语言无所谓,关键是看重构的场景以及重构的思想。git

“重构”不只仅能够改善你既有的代码设计,还能够改变你组织代码的思路,使你的程序在设计之初就趋于合理化,利于程序的扩充。重构每每伴随着设计模式的使用,在重构系列的博客结束后,我想系统的给你们分享一下关于设计模式的东西。固然是结合着各类实例。所谓一名Coder,重构和设计模式是必须涉猎的部分,由于这二者可让你写出更漂亮的代码,固然要想真正的掌握设计模式以及各类重构手法,还得结合不一样的实例来进行实践。理论当然重要,可是要想将理论的东西变成你本身的,还必须将理论付诸实践。废话少说,进入今天的主题。github

一.Pull Up Field (字段上移) & Pull Down Field (字段下移)设计模式

字段上移与字段下移是相对的,也是咱们以前所说的“凡事都有其两面性”,咱们要辩证的去看待。咱们只对Pull Up Field (字段上移) 这个规则作讨论,那么关于Pull Down Field (字段下移)咱们不作过多的讨论,由于这两条规则是相反的,理解一条后,把这条规则反过来就是咱们要理解的另外一条规则。这样提及来,仍是比“触类旁通”要容易的多。框架

下方这个实例是为了解释“字段上移”所实现的一个Demo。固然Demo看上去不只简单并且是有些夸张的,不过说明字段上移这个规则是彻底足够了的。好比咱们有一个父类为MySuperClass,咱们有一个子类SubClass1,而在SubClass1中有一个字段父类是没有的。由于后期需求迭代或者需求变动,咱们须要再建立一个SubClass1的兄弟类,就是下方的SubClass2。在SubClass2中与SubClass1中存在相同的字段,那就是var a = 0函数

    

 

 在上述状况下,就须要使用到咱们的“字段上移”的规则。也就是说将子类中相同的字段移到父类中。在该实例中就是讲var a = 0 移到父类中。重构后的代码以下所示:spa

而将“Pull Down Field (字段下移)正好与上面的状况相反。也就是父类中有某些字段,可是这些字段只有在少数子类中使用到,在这种状况下咱们须要将这个字段移到相应的子类中便可。除了Pull Up Field (字段上移) & Pull Down Field (字段下移) 这两个规则外,Pull Up Method (将函数上移) 和 Pull Down Method (将函数下移)这两个规则与上述状况相似。就是将上面的字段改为函数,有时候不只字段会出现上述状况,函数也会出现上述状况,须要咱们进行移动。由于使用场景相似,再次就不作过多的赘述了。设计

 

2、Extract Subclass (提炼子类)3d

这种状况下用的仍是比较多的,当类中的某些方法只有在特定的类的实例中才会使用到,此时咱们就须要提炼出一个子类,将该方法放到相应的子类中。这样一来咱们的每一个类的职责更为单一,这也就是咱们常说的“单一职责”。代理

在下方示例中,CustomerBook是一个图书消费者的类。其中customeCharge()方法是普通用户计算消费金额所需的方法,而vipCharge()方法是VIP用户调用的方法,在内部vipCharge()须要调用customeCharege()方法。可是对外部而言,vipCharge()方法只有VIP用户才会用到,在这种状况下咱们就须要使用“Extract Subclass (提炼子类)规则对VIP进行提炼。orm

    

 

具体作法是咱们须要提炼出一个子类,也就是说将VIP用户做为普通用户的子类,而后将只有VIP用户才调用的方法放到咱们的VIP子类中。这样一来层次更加明确,每一个类的职责更为单一。上述示例重构后的结果以下所示。

   

与“提炼子类”规则相对应的是“Collapse Hierarchy (折叠继承关系)”。一句话来归纳:就是当你的父类与子类差异不大时,咱们就能够将子类与父类进行合并。将上面的示例翻转就是“Collapse Hierarchy (折叠继承关系)”规则的示例,再次就不作过多的赘述了。

 

3、Form Template Method (构造模板函数)

Form Template Method (构造模板函数)这一规则仍是比较实用的。先说模板,“模板”其实就是框架,没有具体的实现细节,只有固定不变的步骤,能够说模板不关心具体的细节。举个栗子🌰,像前段时间比较火的“秘密花园”,那些没有颜色的线条就是模板,若是一些人获取的是同一本秘密花园,那么说明每一个人所获取的模板是相同的。可是每一个人对每块的区域所图的颜色又有差别,这就是实现细节的不一样。

言归正传,当两个兄弟类中的两个函数中的实现步骤大体一直,可是具体细节不一样。在这种状况下,咱们就能够将大致的步骤提取成模板,放到父类中,而具体细节由各自的子类来实现。具体实现请看下方的类,在Subclass1Subclass2中的calculate()方法中的大致步骤是相同的,就是对两个值相加,而后返回这两个值的和。可是具体细节不一样,能够看出两个相加值的具体计算方式不一样。

  

 

在上述状况下咱们就可使用“Form Template Method (构造模板函数)规则将相同的计算流程进行提取,也就是构造咱们的模板函数。将模板函数放到两个类的父类中,而后在相应的子类中只给出实现细节便可。下方代码段是重构后的代码,父类中多出的方法就是咱们提取的模板函数,而子类中只给出相应的实现细节便可。

  

 

4、以委托取代继承(Replace Inheritance with Delegation

有时候咱们为一些类建立子类后,发现子类只使用了父类的部分方法,并且没有继承或者部分继承了父类的数据。在这种状况下咱们就能够将这种继承关系修改为委托的关系。具体作法就是修改这种继承关系,在原有子类中添加父类的对象字段,在子类中建立相应的方法,在方法中使用委托对象来调用原始父类中相应的方法。

下方示例是咱们假想出来的,可是说明该规则是绰绰有余了。咱们假设SubClass01类中只会用到SuperClass01中的display()方法,而没有继承父类中的数据。在下方示例中是继承关系,在这种状况下咱们须要将其转换成委托关系。

  

下方是咱们重构后的代码,在下方代码中咱们去除了以前的继承关系。并在子类中建立了一个以前父类的代理对象,而且建立了一个相应的方法,在该新建的方法中经过代理对象来调用相应的方法。具体以下所示。

  

上述规则与以继承取代委托Replace Delegation with Inheritance)原则相对于,使用状况与上述相反,再次就不作过多的赘述了。

几天博客就先到这儿,内容比较简单,可是仍是比较重要的。

上述Demo分享地址:https://github.com/lizelu/CodeRefactoring-Swift

相关文章
相关标签/搜索