• 代码重构(二):类重构规则


    在上篇博客《代码重构(一):函数重构规则(Swift版)中,详细的介绍了函数的重构规则,其中主要包括:Extract Method, Inline Method, Inline Temp, Replace Temp with Query, Introduce Explaining Variable, Split Temporary Variable, Remove Assignments to Parameters, Replace Method with Method Object等。关于上述这些函数重构的规则更为详细的信息请参考上一篇博客,在此就不做过多的赘述了。

    今天这篇博客主要介绍一下类的重构。在我们写代码时,有些类是不规范的,需要重构。在对类进行重构时,也是有一些章法可寻的,本篇博客就结合着相关 示例,对类的重构进行相关的介绍。当然在本篇博客中使用的实例,还是延续上一篇文章的风格,仍然采用Swift语言进行编写。当然,还是那句话,重构的思 想和手法与设计模式类似,都与具体语言实现无关。触类旁通,关键还是思想和手法。为了精简博文的篇幅,相关的测试用例就不往上粘贴了。当然,在你实现时, 测试用例是必不可少的,因为测试用例可以在你重构时及时发现因为重构而产生的错误。言归正传,进入今天博客的主题。

     目录:

    一、方法迁移

    二、字段迁移

    三、提炼新类

    四、类的内联化

    五、隐藏委托关系

    六、移除中间人

    七、引入外加函数(继承,包装两种实现方法)

    一、Move Method----方法迁移

    关于Move Method,首先谈论一下为什么要进行方法的迁移。原因很简单,就是当类中的方法不适合放在当前类中时,就应该为该方法寻找合适下家。那么怎样才可以称作是当前方法不适合在当前类中呢?一个类中的函数与另一个类有很多的交互,函数非常依赖于某个类。如果一个类有太多行为,或者与另一个类有太多合作而形成高度耦合。此时就应该将该方法搬移到其高度依赖的类中。

    在给方法搬家时需要做的就是在方法的新家中创建一个方法,实现要搬移的功能,如果新创建的函数需要旧类中的数据,那么就创建一个委托对象来解决这个问题。说白了就是在另一个类中创建一个相同的功能的新函数,将旧函数变成一个单纯的委托函数,或者将旧函数完全移除。搬移后,我们可以再使用函数的重构规则对新组的函数进行重构。下方就通过一个实例来直观的感受一下Move Method。

    1.代码实例

    在下方截图中有两个类,一个Book类,另一个是BookCustomer类。在Book类中有两个属性,一个 是bookCode:表示书的种类(NEW_BOOK,OLD_BOOK, CHIDREN_BOOK), 另一个属性就是书名bookName。在BookCustomer中有3个字段,name表示用户的名称,isVip表示用户是否是会员,books表示 该用户所购买的书的集合。BookCustomer类中的charge()方法用来根据books数组来计算图书的总价格,并返回总价格。如果是VIP, 就在总价格的基础上打7折,普通用户打8折。下方截图就是其具体实现。

       

    2.使用Move Method进行重构

    首先我们对上述两个类进行分析,观察需要重构的地方。首先第一眼看代码时,较长的charge()函数会让我们看起来些微的不舒服,因为它太长了。 再仔细分析,其中的Switch语句中的业务逻辑用的全是Book类的东西,和当前BookCustomer类没用什么关联。但是这个Switch语句是 当前charge()函数的核心,也就是BookCustomer严重依赖Book类的地方。以此分析下去,我们就清楚的指定,该Switch语句块放错 了地方,它应该放在Book类中。所以我们应该将这块代码进行搬移。

    重构方法就是在Book类中创建一个charge()函数,将Switch语句块放入新的charge()函数中。然后在原来的charge()函数使用Switch语句时调用新的charge()方法。下方代码段是使用Move Method重构后的结果。

        

    3.使用函数重构

    在使用Move Method重构后,我们看出在BookCustomer类中的charge()函数是可以使用Extract Method和Replace Temp With Qurey进行重构的。关于这两个函数重构的规则的具体细节请参见《代码重构(一):函数重构规则(Swift版)》中的介绍。下方截图是对BookCustomer类中的charge()函数进行重构后的结果,如下所示:

       

    二、Move Field----搬移字段

    上一部分是搬移方法,Move Field(搬移字段)与Move Method适用场景类似。当在 一个类中的某一个字段,被另一个类的对象频繁使用时,我们就应该考虑将这个字段的位置进行更改了。Move Field与Move Method的思想和做法差不多,再次对其的示例就省略了。举一反三,你可以类比着Move Method来使用Move Field规则。具体实现方式在此就不做过多的赘述了。

    三、Extract Class----提炼类

    Extract Class和Extract Method类似,Extract Method提取的是方法,而Extract Class提取的是类。一个类如果过于复杂,做了好多的事情,违背了“单一职责”的原则,所以需要将其可以独立的模块进行拆分,当然有可能由一个类拆分出 多个类。当然,对类的细化也是为了减少代码的重复性,以及提高代码的复用性,便于代码的维护。下方将会通过一个实例,对类进行提炼。

    1.重构前的代码

    下方是我们将要进行重构的代码段。在Person类中有三个字段,常量name表示该Employee的名字,officeAreaCode表示Employee所在办公部门的区域代码。然后就是Employee类的构造函数了。Employee类比较简单。

       

    2.使用Extract Class对Employee重构

    接下来要做的就是使用Extract Class对Employee进行重构。因为上述Employee类设计的不好,因为Employee 类可以再分。显然可以将区域号和电话号提取成一个TelePhoneNubmer类,在Employee中调用TelePhoneNubmer类。这样一 来TelePhoneNubmer类就可以重复利用了,而且层次结构更为清晰。下方代码段就是对上述代码进行重构后的结果。具体如下所示:

    四、Inline Class----类的内联化

    又到了“物极必反”的时候了。Extract Method与Inline Method职责相反,Extract Class当然也就职责相反的原则。那就是接下来要介绍的类的内联化:Inline Class。如果过度使用Extract Class原则的话,会使得某些类过于简单并且调用该简单的类的地方极少。也就是说一个类根本不能称为一个类,所以我们可以通过Inline Class将过度抽象出来的类放到其他类中。

    关于Inline Class的示例在此就不做过多的赘述了,因为与Extract Class原则相反,将第三部分中的示例倒着过一遍即为类的内联化的工作方式。

    五、Hide Delegate----隐藏委托关系

    隐藏类之间的“委托关系”这一原则用起来是非常不错的,它可以简化类调用委托者的方式。简单的说就是讲委托调用的链,封装成相应的方法,使其隐藏掉具体的调用细节,从而简化了调用方式。下方会根据具体事例和测试用例来介绍一下Hide Delegate。

    1.重构前的案例

      在下方代码片段中有两个类,这两个类互为依赖关系。Department中有People,该People对应的就是经理人。还有一个字段就是 chargeCode,对应的是部门代码。而People类中有name--名字字段,department--所属部门字段。在People对象中可以 委托department对象来获取经理的名字。

        

      获取People对象所在部门经理的名字的测试用例如下所示。在下方测试用例中创建了一个经理和一个员工,并为员工和经理绑定关系。zeluLi.department.manager.name就是委托department对象来调用经理的名字,这样调用未免太长,所以有必要使用Hide Delegate原则对其进行优化。

       

    2.使用Hide Delegate进行重构

    使用Hide Delegate进行重构的方式是比较简单的,就是在People中封装一个方法,在方法中返回经理的对象即可,这样就隐藏掉了委托关系。具体实现方式如下截图所示:

        

     添加上上面的函数后的调用方式如下:

        

    Remove Middle Man(移除中间人)原则与Hide Delegate相反,就是没有必要将委托人进行隐藏,所以就使用Remove Middle Man原则将上面我们封装的获取委托人的方法进行移除。关于Remove Middle Man的范例就不做过多的赘述了。

     

    六、Introduce Foreign Method----引入外加函数

    这一点在开发中用的还是比较多的,有时候你在不想或 者不能修改原类的情况下想为该类添加新的方法。在这种情况下就会使用到Introduce Foreign Method。在Swift语言中,使用Introduce Foreign Method原则特别简单,也就是在不改变类的情况下对类进行扩展也是特别简单的。因为Swift语言以及OC中有延展的功能,所以非常对此非常好实现 的。下方的代码段就是对MyTest类使用extension为其扩展一个method2方法,具体如下所示。

       

     

    今天的博客就先到这儿,后期还会继续更新关于重构的博客。本篇博客中的代码分享地址为:https://github.com/lizelu/CodeRefactoring-Swift

  • 相关阅读:
    sgu209:Areas(计算几何)
    altium designer电气符号和包的常用元素
    wxWidgets谁刚开始学习指南(5)——使用wxSmith可视化设计
    zoj 3820 Building Fire Stations(二分法+bfs)
    iOS 注册或登录页面(UILable,UITextField,UIButton)
    [ACM] POJ 2689 Prime Distance (筛选范围大素数)
    数字签名和数字证书技术简介(两)
    [Node] Using dotenv to config env variables
    [TypeStyle] Compose CSS classes using TypeStyle
    [Node] Use babel-preset-env with Native Node Features and Also Use Babel Plugins
  • 原文地址:https://www.cnblogs.com/tianzhiyi/p/5340903.html
Copyright © 2020-2023  润新知