重构--封装

本文探讨了编程中的几种关键重构策略,包括封装记录和集合、对象设计、数据项升级、查询优化、类责任分解、内联类、隐藏委托关系以及中间人模式的移除,以提高代码可维护性和性能。
摘要由CSDN通过智能技术生成
  1. 封装记录
    动机:记录型结构是多数编程语言提供的一种常见特性。他们能直观地组织起存在关联的数据,让数据作为有意义的单元传递。同时它强迫区分“记录中存储的数据”和“通过计算得到的数据”。对象可以隐藏结构的细节,使对象的用户不需要追究存储的细节和计算过程。另外如果修改字段时,用户可以重命名字段,但同时提供新老字段名的访问方法,这样可以渐进地修改调用方,直到全部替换。

    做法:

    • 对持有记录地变量使用封装变量,将其封装到一个函数中。
    • 创建一个类,将记录包装起来,并将记录变量地值替换为该类的一个实例。然后在类上定义一个访问函数,用于返回原始的记录。修改封装变量的函数,令其使用这个访问函数。
    • 测试。
    • 新建一个函数,让它返回该类的对象,而非那条原始记录。
    • 对于该记录的每处使用点,将原先返回记录的函数调用替换为那个返回实例对象的函数调用。使用对象上的访问函数来获取数据的字段,如果该字段的访问函数还不存在,就创建函数。每次更改后进行测试。
    • 移除类对原始记录的访问函数,测试。
    • 如果记录中的字段本身也是复杂结构,考虑对其再次应用封装记录封装集合方法。
  2. 封装集合
    动机:封装集合时人们常常犯一个错误:只对集合变量的访问进行了封装,但是依然让取值函数返回集合本身。这使得集合的成员变量可以直接被修改,而封装它的类则全然不知,无法介入。

    做法:

    • 如果集合的引用尚未被封装起来,想用封装变量封装他。
    • 在类上添加用于“添加集合元素”和“移除集合元素”的函数。
    • 执行静态检查。
    • 查找集合的引用点。如果有调用者直接修改集合,令该处调用使用新的添加/移除元素的函数。测试。
    • 修改集合的取值函数,使其返回一份只读的数据,可以使用只读代理或数据副本。
    • 测试。
  3. 以对象取代基本类型
    动机:开发初期,使用一个简单的数据项就可以表示简单的情况,比如使用字符串或数字等。但随着开发的进行,简单的数据项可能不能够表达其原本的含义。例如:开始用字符串表示“邮箱地址”,但之后又要进行“格式化”、“获取域名”等之类的特殊操作。如果再增加单一的字符串,就会制造出许多重复的代码。

    做法:

    • 如果变量尚未封装,先使用封装变量封装。
    • 创建类。用类的构造函数保存这个数据值,并为它提供一个取值函数。
    • 执行静态检查。
    • 修改第一步得到的设置函数,令其创建一个新类的对象并将其存入字段,如果有必要的话,同时修改字段的类型声明。
    • 修改取值函数,令其调用新类的取值函数,并返回结果。
    • 测试。
  4. 以查询取代临时变量
    动机:将变量抽取成函数能够使函数分解过程更简单,因为不在需要将变量作为参数传递给函数。将变量的计算逻辑放到函数中,也有助于在函数与函数之间设立清晰的边界。同时也避免了在多个函数中重复编写计算逻辑。

    做法:

    • 检查变量在使用前是否已经完全计算完毕,检查计算代码是否每次都能得到一样的值。
    • 如果变量目前不是只读,但是可以改造成只读变量,就先改造。
    • 测试。
    • 将为变量赋值的代码提炼成函数,确保提炼函数没有副作用。
    • 测试,移除临时变量。
  5. 提炼类
    动机:

    • 类的责任随着业务的添加变得过分负载,不易理解。
    • 子类化只影响类的部分特性,或者发现某些特性需要以一种方式来子类化,某些特性则需要另一种方式子类化。

    做法:

    • 决定如何分解类所负的责任。
    • 创建新的类,用以表现从旧类中分离出来的责任。
    • 构造旧类时创建一个新类的实例,建立“从旧类访问新类”的链接关系。
    • 对于想要迁移的字段,每次更改后运行测试。
    • 将必要函数迁移到新类中。先迁移较底层函数(即“被其他函数调用”多于“调用其他函数”的函数),测试。
    • 检查两个类的接口,去掉不需要的函数。
    • 决定是否公开新类。如果需要,考虑将新类应用改为一个值对象。
  6. 内联类
    动机:

    • 一个类不在承担足够的责任,不在有单独存在的理由(通常是因为之前的重构移走了这个类的责任)。
    • 要重新安排两个类的职责,并让它们产生关联。

    做法:

    • 对于待内联类(源类)中的所有public函数,在目标类上创建一个对应的函数,新创建的所有函数应该直接委托至源类。
    • 修改源类public方法的所有引用点,令它们调用目标类对应的委托方法。测试。
    • 将源类中的函数与数据全部搬移到目标类,每次修改之后进行测试,直到源类变为空壳为止。
    • 删除源类。
  7. 隐藏委托关系
    动机:每个模块应该尽可能少了解系统的其他部分。如此一来,一旦发生变化,需要了解这一变化的模块就比较少,这会使变化比较容易进行。

    做法:

    • 对于每个委托关系中的函数,在服务对象端建立一个简单的委托函数。
    • 调整客户端,令他只调用服务兑现提供的函数,每次调整后测试。
    • 如果将来不在有任何客户端需要取用Delegate(受托类),便可移除服务对象中的相关访问函数。
    • 测试。
  8. 移除中间人
    动机:随着受托类的功能越来越多,更多的转发函数会使人烦躁。服务类完全变成了一个中间人,此时就应该让客户直接调用受托类。

    做法:

    • 为受托对象创建一个取值函数。
    • 对于每个委托函数,让其客户端转为连续的访问函数调用。每次替换后测试。
  9. 替换算法
    动机:有更简单的解决方案时,需要改变原先的算法。更改之前要确定已经尽可能地分解了原先地函数。

    做法:

    • 整理待替代地算法,保证它已经被抽取到一个独立的函数中。
    • 先为函数准备测试,以便固定它的行为。
    • 准备好另一个算法。
    • 执行静态检查。
    • 测试。
  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值