美文网首页
重构(笔记)——第七章

重构(笔记)——第七章

作者: 宿命99 | 来源:发表于2019-09-30 13:23 被阅读0次

在对象之间搬移特性

“决定把责任放在哪儿”

搬移函数

一个类有太多的行为,或者如果一个类与另一个类有太多使用而形成的高度耦合,就需要搬移函数。

// 书中的示例
class Account {
  private AccountType _type;
  private int _daysOverdrawn;
  
  double overdraftCharge() {
    if (_type.isPermium()) { // isPermium() 属于 AccountType 的函数
      double result = 10;
      if (_daysOverdrawn > 7) {
        result += (_daysOverdrawn - 7) * 0.85;
      }
      return result;
    } else {
      return _daysOverdrawn * 1.75;
    }
  }
  
  double bankCharge() {
    double result = 4.5;
    if (_daysOverdrawn > 0) {
      result += overdraftCharge();
    }
    return result;
  }
}

// 重构后
class Account {
  private AccountType _type;
  private int _daysOverdrawn;
  
  int getDaysOverdrawn(){
    return _daysOverdrawn;
  }
  
  double bankCharge() {
    double result = 4.5;
    if (_daysOverdrawn > 0) {
      result += _type.overdraftCharge(this);
    }
    return result;
  }
}

class AccountType {
  double overdaftCharge(Account account) {
    if (isPermium()) {
      double result = 10;
      if (account.getDaysOverdrawn() > 7) {
        result += (account.getDaysOverdrawn() - 7) * 0.85;
      }
      return result;
    } else {
      return account.getDaysOverdawn() * 1.75;
    }
  }
}

将函数由一个类迁移到另一个类,在迁移过程中需要注意的问题是所有依赖的方法也必须相应的进行修改。

搬移字段

将一个类的字段由本类迁移到另外一个类中。

// 书中的示例
class Account {
    private AccountType _type;
    private double _interestRate;
    
    double interestForAmount_days (double amount, int days) {
        return _interestRate * amount * days / 365;
    }
}

// 重构后
class AccountType {
    private double _interestRate;
    
    void setInterestRate(double arg){
        _interestRate = arg;
    }
    
    double getInterestRate() {
        return _interestRate;
    }
}

class Account {
    private AccountType _type;
    
    double interestForAmount_days (double amount, int days) {
        return _type.getInterestRate() * amount * days / 365;
    }
}

搬移字段与搬移函数基本类似,只是操作的对象不一样,一个是操作的函数,一个操作的是字段(成员变量)。

提取类

一个类应该是一个清楚的抽象,处理一些明确的责任。

而现状是,在增加一些功能是,基本都放在一个类中,类会越来越大,越来越复杂。而解决这一问题的办法就是将这些本该拆分成多个类的代码提取出来,放入一个新的类中。

// 书中的示例
class person {
    private String _name;
    private String _officeAreaCode;
    private String _officeNumber;
    
    public String getTelephoneNumber() {
        return ("(" + _officeAreaCode + ") " + _officeNumber);
    }
    
    String getOfficeAreaCode() {
        return _officeAreaCode;
    }
    
    void setOfficeAreaCode(String arg) {
        _officeAreaCode = arg;
    }
    
    String getOfficeNumber() {
        return _officeNumber;
    }
    
    void setOfficeNumber(String arg) {
        _officeNumber = arg;
    }
}

// 重构后,书中将其提取出了一个 TelephoneNumber 类
class TelephoneNumber {
    private String _areacode;
    
    String getAreaCode() {
        return _areaCode;
    }
    
    void setAreaCode(String arg) {
        _areaCode = arg;
    }
}

class Person {
    public String getTelephoneNumber() {
        return ("(" + getOfficeAreaCode() +") " + _officeNumber);
    }
    
    Strng getOfficeAreaCode() {
        return _officeTelephone.getAreaCode();
    }
}
// 将原本属于 Person 类中的 _officeAreaCode 和 _officeNumber 封装到 TelphoneNumber 类中

将类内联化

提取类 正好相反,某个类没有做太多事情,将这个类的所有特性搬移到另一个类中,然后移除原类。

// 案例与上一个正好相反,把 TelephoneNumber 类内联到 Person 类中,然后删除 TelephoneNumber 类

思考:某些重构手法正好是两个相反的操作,一个添加,一个移除。如何选择哪个手法才是见功力的,我目前的判断是,看复杂程度,过于复杂就添加,原本有多余的而且就很简单,就删除。

隐藏"委托关系"

“封装”即使不是对象的最关键特征,也是最关键特征之一。

如果某个客户先通过服务对象的字段得到另一个对,然后调用后者的函数,那么客户就必须知晓这一层委托关系。万一委托关系发生变化,客户也得相应进行变化。这时的作法是,可以在服务对象上放置一个简单的委托函数,将委托关系隐藏起来,从而去除这种依赖。

// 书中的示例
class Person {
    Department _department;
    
    public Department getDepartment() {
        return _department;
    }
    
    public void setDepartment(Department arg) {
        _department = arg;
    }
}

class Department {
    private String _chargeCode;
    private Person _manager;
    
    public Department(Person manager) {
        _manager = manager;
    }
    
    public Person getManager() {
        return _manager;
    }
}
// 调用 
manager = john.getDepartment().getManager();

// 重构后 
class Department {
    private String _chargeCode;
    private Person _manager;
    
    public Department(Person manager) {
        _manager = manager;
    }
    
    public Person getManager() {
        return _manager;
    }
}
// 调用 
manager = john.getManager();

移除中间人

当类提供的函数复杂到一定程度时,我们为了隐藏 ”委托关系“ 而添加的函数越来越多时,索性将 ”委托关系“ 暴露出来,供调用方直接调用。

隐藏“委托关系” 正好相反的操作。

// 示例代码与上面相反,去除 Department 类中的 getManager() 方法,直接暴露出 getDepartment() 方法获取中间人,然后调用对应的函数以实现其目的。

引入外加函数

当某个函数需要扩展,而我们无法直接修改这个类时,可以增加函数来实现该功能。

// 书中的示例
Date newStart = new Date(previousEnd.getYear(), previousEnd.getMonth(), previousEnd.getDate() + 1);

// 重构后
private static Date nextDay(Date arg) {
    return new Date(arg.getYear(), arg.getMonth(), arg.getDate() + 1);
}

我们在项目中开发代码时,经常会写一些工具类(XxxUtils),其实跟这个重构手法是差不多一个操作。

引入本地扩展

与上面的需求基本一致,我们无法直接修改这个类,但需要在这个类的基础上进行一些扩展。此时我们可以有两种 做法:

  • 扩展出一个子类
  • 增加一个包装类
// 书中的示例
class MfDateSub extends Date {
    public MfDateSub nextDay() {
        ...
    }
    
    public int dayOfYear() {
        ...
    }
}

// 包装类
class MfDateWarp {
    private Date _original;
    
    public MfDateSub(String dateString) {
        _original = new Date(dateString);
    }
    
    public MfDateWarp(Date date) {
        _original = date;
    }
}

参考资料:
[1]: https://book.douban.com/subject/4262627/ "重构-改善既有代码的设计"

相关文章

  • 重构(笔记)——第七章

    在对象之间搬移特性 “决定把责任放在哪儿” 搬移函数 一个类有太多的行为,或者如果一个类与另一个类有太多使用而形成...

  • #30天橙长计划#Day15沟通

    《沟通的艺术》读书笔记——第七章 倾听不只是听见 7.1倾听的定义 听是一个耳膜振动传送到大脑的过程,倾听是重构原...

  • 改善既有代码的设计笔记(三)代码的坏味道

    前面两篇笔记涉及到了部分重构的时机,本篇笔记全部为重构代码的时机。重构时机,不是僵硬死板的必须在什么时候执行,下面...

  • 《重构》读书笔记 第七章

    在对象之间迁移数据 7.1 Move Method (搬移函数) 如果一个类有太多行为,或如果一个类与另一个类有太...

  • 重构读书笔记-7_7-Introduce_Foreign_Met

    重构第七章 7.Introduce Foreign Method(引用外加函数) 你所使用的server clas...

  • 重构读书笔记-7_8-Introduce_Local_Exten

    重构第七章 8.Introduce Local Extension(引入本地扩展) 你所使用的server cla...

  • 重构:读书笔记

    重构读书笔记 第一章 重构,第一个案例 第二章 重构原则 2.1 何为重构 重构(名词):对软件内部结构的一种调整...

  • 如何实施代码重构?

    阅读《重构》的笔记献上。 重构的定义 重构是在不改变软件可观察行为的前提下改善其内部结构。 重构的节奏 以微小的步...

  • 重构读书笔记-7_5_Hide_Delegate

    重构第七章 5.Hide Delegate(隐藏委托) 客户端直接调用server object(服务对象)的de...

  • 重构 笔记

    本书针对单进程软件,书中的重构方法不一定适用于分布式软件 第一章 ,重构——第一个案例 代码结构使得添加新特性异常...

网友评论

      本文标题:重构(笔记)——第七章

      本文链接:https://www.haomeiwen.com/subject/ahgcpctx.html