前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >代码重构(五):继承关系重构规则

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

作者头像
lizelu
发布2018-01-11 11:30:44
13.4K0
发布2018-01-11 11:30:44
举报
文章被收录于专栏:青玉伏案青玉伏案青玉伏案

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

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

一.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 移到父类中。重构后的代码如下所示:

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

二、Extract Subclass (提炼子类)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-03-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档