第三步:提高代码复用率
经过重构的第一步,我们将令人头疼的大函数分解成了大小适中的一个个小函数,经过重构第二步,我们将无所不能的大对象拆分成了功能内聚的一个个小对象。随后,我们需要考虑的问题就是优化我们的代码了。
1. DRY原则:Don't Repeat Yourself.
2. 如何识别相似或相近功能?
a. 处理同一流程中某个环节而采用的不同方式,如购物付款方式不同,但结果相同,此时,可将付款结果合并成一个类或方法,将不同的付款流程抽象成一个接口下的多个实现类。
b. 在不同业务中某个功能相似或相近的环节,如填写各类单据时的校验环节,校验数据,校验用户等等。
c. 本身就相似或相近的功能,将相同代码抽象为父类或公用类,保留不同代码在原程序中。
3. 如何重构,或者说如何提高代码复用?
它需要有相当的面向对象分析与设计理论知识与相当的分析设计经验。不论怎样,重构的第一步是比较代码。
a. 当重复代码存在于同一对象中时——抽取方法
当看到同一个类中几个方法均出现了相同的几行代码时,可以将这几行代码抽取成一个单独的方法,再对其进行调用。
b. 当重复代码存在于不同对象中时——抽取类
比较直观的方法就是运用“抽取类”将共同的部分抽取到一个工具类中,比如我们常见的对数据库的操作,将公有方法写入SqlHelper类中,以此为其他各类所调用。采用工具类的方法非常实用,被合并的代码即使分散在系统的各个角落,各自功能没有任何联系,都可以采用。当一个需求变更导致分散在各处的代码修改时仅需修改工具类中对应的方法。
c. 不同对象中复用代码的另一种方法——封装成实体类
与上述方法比较类似的一种方法就是提取并封装成实体类,实体类内部存在着较强的业务相关性。工具类仅仅表现为一堆方法的集合,实体类体现的是一定的业务逻辑,并在使用时需要实例化。
d. 当代码所在类具有某种并列关系时——抽取父类
i. 整理原有代码,抽取函数
ii. 抽取父类,从多个要重构的类中抽取一个共同的父类
e. 当出现继承泛滥时——将继承转换为组合
组合与继承的对应关系:
组 合 关 系 |
继 承 关 系 |
局部类 |
父类 |
整体类 |
子类 |
从整体类到局部类的分解过程 |
从子类到父类的抽象过程 |
从局部类到整体类的组合过程 |
从父类到子类的扩展过程 |
f. 当重复代码被割裂成碎片时——继承结合模板模式
模板模式是GoF设计模式中的一个,如果你为一个算法定义了一系列步骤,并且允许子类来实现其中的一个或多个步骤,你就可以使用这个模式。该方法将把分离得支离破碎的程序过程,分解成数个方法定义在模板模式的父类中,将不同的部分分别在子类中实现。
在我们开发过程中有效地建立起持续集成环境,常常是保证代码质量非常重要的手段之一。
第四步:发现程序可扩展点
我们进行系统重构,其中一个重要的目的就是使系统能够更加轻松地应对系统需求的变更,即提高系统的易变更性。
开放-封闭原则: OCP, Open-Close Principle,当系统需求发生变更时,我们可以对软件功能进行扩展,使其满足新的需求。
1. 如何避免因新需求所做的修改为原有功能引入bug?
最好的办法是在不修改原有代码的基础上实现新的功能,最关键的就是要将原有代码与新代码有效地隔离。
2. 可扩展设计的关键是?
先重构原有代码,使其具有可扩展功能,再添加新程序,使其满足OCP原则。
3. 当新需求到来时如何进行设计?
a. 在不增加新功能的条件下实现可扩展功能
b. 运用“抽取接口”去归纳各个不同的类,从而抽取出共同的方法放到接口中
c. 实现接口的配置与调用
4. 什么是hook?它有什么作用?
hook是一个空函数,调用它就如同什么都没有调用一般。但hook如果被放在了抽象类中,作用就非常大了。如果抽象类的子类要使用它时,则重载这个函数,为其编写各自的代码,完成相应操作,而其他子类如果不使用它,则什么也不用做。
5. 扩展点设计方法:
a. 开放-封闭原则
b. 过程的扩展与放置钩子——运用模板模式增加可扩展点
c. 面向切面的可扩展设计(AOP:Aspect Oriented Programming编程)
第一种设计使用于if-else或者switch这样的条件切换语句,第二种设计适用于拥有相似操作步骤的一系列操作中,第三种适用于在某些操作前后有不确定的前置或后续操作时。
6. 当新需求到来时,我们应当有足够的意识,让这种代码的修改符合OCP原则,这是保证软件质量不会下降的一个非常重要的措施之一。