重构

函数

  1. 提炼函数
    将大函数提炼成多个小函数,当某个代码片需要注释解释功能时,既可以被提取为一个单独的函数。
    如果有局部变量,若局部变量没有被修改,可以直接当做参数传入;如果被修改,可以当做返回值。若不止一个被修改,则分解为多个函数。

  2. 内联函数
    如果函数体的解释性比函数名更好,且复用不高,则取消函数,将函数体插入到代码片中。

  3. 内联临时变量
    如果有个临时变量只被赋值了一次,起作用的时候妨碍了其他的重构手法,则取消临时变量,直接使用赋值表达式。

  4. 查询替代临时变量
    临时变量只能函数内使用,将其提取为函数,则整个类都可以使用,减少参数传递。

  5. 引入解释性变量
    较长算法中难以阅读,将长表达式分解为多个解释性临时变量,更好阅读和理解。

  6. 分解临时变量
    临时变量应该只承担一个功能,不应该被不同的事件重复赋值使用,会导致阅读困难。尝试新建临时变量承担别的事情。

  7. 移除对参数的赋值
    Java按值传递(对于对象其实也是引用的值传递),入参的改变不会对调用者产生影响,为了突出改变,应该新建一个临时变量进行操作。

  8. 以函数对象取代函数
    如果函数中存在大量临时变量,可以将函数提取成一个类,临时变量作为类的成员,函数体变成类的compute()方法,然后可以进行其他的重构方法。

  9. 替换算法
    一定存在某个算法比另一个算法更好,使用更好的算法替换。

对象

  1. 搬移函数
    如果一个类中的函数更高频次的被另一个类对象调用,应该将其搬移至新类中,原函数将操作委托给新类,或删除原函数。

  2. 搬移字段
    在新类中建立名字相同的字段,并删除原字段,根据编译器报警修改引用,如果有太多引用,修改访问函数set()、get()使其访问新类字段。

  3. 提炼类
    类越来越复杂,如果类中某些数据和某些函数经常一起发生变化,或者发现子类化只影响部分的属性,应该考虑提取到新类中去。新类和旧类之间可能需要连接,但只有在真的需要时才去建立连接。注意,新类和旧类分离会导致权限的改变从而产生事物问题,新类的改变要依托于旧类还是独立改变要取决于具体场景

  4. 类内联化
    如果类起的作用很小,应该将其合并到其他类中,修改权限符并进行改名,在编译器的帮助下找到所有引用点进行更换。

  5. 隐藏委托关系
    服务端提供委托函数来隐藏真正的委托关系,客户只需要关注委托函数,一旦真正的委托关系发生改变也只会发生在服务端,不会对客户端产生影响。

  6. 移除中间人
    如果存在大量的委托函数是不合理的,此时应该移除委托函数,直接提供受托类对象给客户调用。

  7. 引入外加函数
    如果你需要为提供服务的类增加一个函数,但你无法修改这个类,在客户端新建一个函数并将服务类实例作为第一个参数,该函数不应该调用客户端的任何特性,因为该函数本身就应该处于服务端中。

  8. 引入本地扩展
    当有多个因权限无法新增的函数存在时,建立原始类的子类或包装类(子类会存在父子两个对象,注意数据不一致的情况),将外加函数引入到这个类中。

重组数据

  1. 自封装字段
    通过访问函数访问字段,能够提供更灵活的管理方式。

  2. 以对象取代数值

  3. 值对象改变为引用对象
    从一个类中衍生出很多彼此相等的示例,将它们替换为同一个对象。
    值对象,即类似“jwb”、123等仅代表值的,用equals()判断相等;类似客户与订单,若同一个客户,有多个订单时还对应着多个客户对象,即为值对象。
    引用对象则代表实物,使用=判断相等。类似客户与订单,若同一个客户,有多个订单时只对应一个客户对象,即为引用对象。

  4. 引用对象变为值对象
    当引用对象很小且不可变,不利于管理时。

  5. 以对象取代数组
    若一个数组其中的元素各自代表不同的东西,以对象替代数组,用字段表示每个数组元素。

  6. 复制被监视数据
    有领域数据置身于GUI控件中,而领域函数需要访问这些数据,将该数据复制到一个领域对象中,建立一个Observe模式来同步这些数据。

  7. 单向关联改为双向关联
    两个类都需要使用对方特性,但其间只有一条单向连接;添加一个反向指针,并使修改函数能同时更新两条连接。双向关联更加复杂,增加耦合,可能产生僵尸对象,因此谨慎使用
    反向指针实现(其他技术如连接对象不在这讨论):

  • 再被引用类中添加一个字段,用以保存反向指针。
  • 决定由哪个类——引用端还是被引用端——控制关联关系。
  • 在被控端建立一个辅助函数,其命名应该清楚指出它的有限用途。
  • 如果既有的修改函数在控制端,让他负责更新反向指针。
  • 如果既有的修改函数再被控端,就在控制端建立一个控制函数,并让既有的修改函数调用这个新建的控制函数。
  • 一般为:一控多、主控从。
  1. 双向关联改为单向关联
    两个类之间有双向关联,其中一个类不再需要另一个类的特性,去除不必要的关联。

  2. 字面常量取代魔法值

  3. 封装字段
    public字段值改为private,且提供访问函数。 可能数据隐藏且提供更灵活的管理方式。

  4. 封装集合
    有个函数返回一个集合,让这个函数返回该集合的一个只读副本(Collections.unmodifiableXXX()),并在这个类中提供添加/移除集合元素的函数。

  5. 以数据类取代记录

  6. 以类取代类型码
    符号名只是个别名,编译器关注的是背后的真正的值,如果类型码是纯粹数据不会影响行为,使用类替代,编译器可以对类进行类型检查。

  7. 子类取代类型码
    有一个不可变类型码,会影响类的行为,用子类取代这个类型码(类似switch、if-then-else)。
    将类型码替换为可拥有多态行为的继承体系,以类型码的宿主类为基类,并针对每一种类型码各建立一个子类。
    好处在于把不同行为的了解从类用户转移到了类自身,如果需要加入新的行为变化,只需要添加一个子类,如果没有多态,就必须找到所有条件表达式并逐一修改。

  8. 以State/Strategy取代类型码
    有一个影响类行为的类型码,但无法通过继承消除它,以状态对象取代类型码。新建一个状态码抽象类对象,并以此为基类创造类型子类。

  9. 以字段取代子类
    各个子类的唯一差别只在返回常量数据的函数身上,修改这些函数,是它们返回超类中的某个字段,然后销毁子类。

条件表达式

  1. 分解条件表达式
    将大块条件分支分解为多个独立函数,并重新命名。

  2. 合并条件表达式
    若一系列条件测试都得到相同结果,则将这些测试合并成一个条件表达式,提炼为函数。

  3. 合并重复的条件片段
    再条件表达式的每个分支上有着相同的一段代码,将其搬移到表达式之外。

  4. 移除控制标记
    再一系列布尔表达式中,某个变量带有“控制标记”的作用,用break/return取代控制标记

  5. 以卫语句取代嵌套条件表达式
    一层层的嵌套逻辑难以看清正常执行路径,判断后不符合条件直接返回,取消嵌套逻辑。

  6. 以多态取代条件表达式
    条件表达式根据对象类型有不同的行为,将条件表达式的每个分支放进一个子类内的复写函数中,将原始函数声明为抽象函数。

  7. 引入NULL对象
    将null值替换为NULL对象,建立源类的NULL版本,设置isNull()来辨别,在所有获取源对象却得到null的地方改为获取NULL对象,在与null比较的地方变为判断isNull()
    建立Null接口,创建的源类NULL版本实现这个接口并继承源类,重写源类方法当为null时的情况,并使用instance of判定是否为null对象,无需再用isNull()

简化函数调用

  1. 函数改名
  2. 添加参数
  3. 移除参数
  4. 将查询函数和修改函数分离
  5. 令函数携带参数
    若干函数做了类似的工作,但在函数本体中却包含了不同的值,即只因几个值导致行为略有不同,此时可以将函数统一起来,将那几个值作为参数。
  6. 以明确函数取代参数
    有一个函数完全取决于参数值而采取不同行为,针对该参数的每一个可能值,建立一个独立函数。
  7. 保持对象完整
    当你从某个对象中取出某些值作为函数调用时的参数时,改为传递整个对象。这样以后添加参数时会更方便,且易读性增加。
  8. 以函数取代参数
    B调用A得到的值作为参数给函数C,而C也可以调用A,此时可以去掉这个参数,直接在C中调用A即可。
  9. 引入参数对象
    若某些参数总是很自然的同时出现,以一个对象取代这些参数。
  10. 移除设值函数
    如果类中某个字段应该在对象创建的时候被设值,然后不再改变,应去掉该字段的所有设值函数。
  11. 隐藏函数
    如果某个函数从来没被其他类用过,函数修改为private。
  12. 以工厂函数去掉构造函数
    工厂函数提供更灵活的对象创建方式。
  13. 封装向下转型
    某个函数返回的对象需要由调用者再次向下转型时,将这个向下转型下放到函数中去。
  14. 以异常取代错误码
  • 非受控异常。由调用者负责检查
  • 受控异常是函数自身的责任,应该声明可能产生的异常。
  1. 以测试取代异常
    先提前判断条件是否通过再继续执行程序,不要滥用异常。

概括关系

  1. 字段上移
    多个子类拥有相同的字段,将字段移至超类。
  2. 函数上移
    有些函数在各个子类中产生完全相同的结果,将其移至超类。
  3. 构造函数本体上移
    各子类中拥有一些构造函数,本体几乎完全一致,则在超类中新建一个构造函数,并在子类构造函数中调用它。
  4. 函数下移
    超类中的某个函数只与部分子类有关,下放到子类中去。
  5. 字段下移
    超类中的某些字段只有部分子类用到,下放到子类中去。
  6. 提炼子类
    类中的某些特性纸杯某些实例用到,新建一个子类,将那部分特性移到子类中。
  7. 提炼超类
    两个类有相似特性,建立超类并将相似特性移至超类中。
  8. 提炼接口
    若干客户使用类接口中的同一子集,或两个类的接口有部分相同,将相同的子集提炼到一个独立接口中。
  9. 折叠继承体系
    超类和子类无太大区别,合并。
  10. 塑造模板函数
    有一些子类其中响应的某些函数以相同顺序执行类似操作,但各个操作细节上有所不同,将这些操作分别放入独立函数中,并保持拥有相同签名,然后将原函数上移至超类。
    在这里插入图片描述
  11. 委托取代继承
    某个子类只使用超类接口中的一部分,或根本不需要继承而来的数据,在子类中新建一个字段保存超类,化继承为委托。
  12. 继承取代委托
    两个类之间有委托关系,委托类用到受托类的所有函数,且经常为整个接口编写许多简单的委托函数,则让委托类继承受托类。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值