• 学习重构(3)-在对象之间搬移特性


    1. Move Method(搬移函数)

    在该函数最常用的勒种简历一个有着类似行为的新函数,将就函数变成一个单纯的委托函数,或是将就函数完全移除。

    应用场景:搬移函数是重构理论的支柱,如果一个类有太多行为,或者一个类与另一个类有太多合作而形成高度耦合,我们就需要搬移函数。通过这种手段,我们可以使系统中的类更简单,这些类最终也将更干净利落的实现系统交付的任务。

    示例:

    class A...

      void a1()...

      void a2() {

        B b = new B();

        b.b1();

        b.b2();

      }

    class B...

      void b1()...

      void b2()...

    重构为:

    class A...

      void a2() {

        B b = new B();

        b.b3();

        b.b2();

        b.a1();

      }

    class B...

      void b1()...

      void b2()...

      void a1()...

    2. Move Field(搬移值域)

    在目标类新建一个字段,修改元字段的所有用户,令他们改用新字段。

    应用场景:在类之间移动状态和行为,是重构过程中必不可少的措施。随着系统发展,你会发现自己需要新的类,并需要将原本的工作职责拖到新的类中,当前合理而正确的设计决策,在未来可能不在正确,这没问题,如果你从来没遇到过这种情况,那才有问题。

    示例:

    class A...

      private int id;

      private String name;

    class B...

      private String name;

    重构为:

    class A...

      private String name;

    class B...

      private int id;

      private String name;

    3.Extract Class(提炼类)

    建立一个新类,将相关的字段和函数从旧类搬移到新类

    应用场景:你也许听过类似的教诲:一个类应该是一个清楚的抽象,处理一些明确的责任。但是实际工作中,类会不断成长扩张,你会在这加入一些功能,在那加入一些数据。给某个类添加一项新责任时,你会觉得不值得为这项新责任分离出一个单独的类。于是,随着责任不断增加,这个类变得过分复杂,成为一团乱麻。这样的类往往含有大量函数和数据,因为太大而不易理解。此时需要考虑将哪些部分可以分离出去,放到一个单独的类中。如果某些数据和某些方法总是一起出现,如果某些数据经常同时变化甚至彼此相依,这就表示它们应该被分离出去。

    示例:

    class Team...

      private String engineer1;

      private String engineer2;

      private String tester1;

      private String tester2;

    重构为:

    class Team...

      Engineer engineerTeam;

      Tester testerTeam;

    class Engineer ...

      private String engineer1;

      private String engineer2;

    class Tester...

      private String tester1;

      private String tester2;

    4. Inline Class(将类内联化)

    将这个类的所有特性搬移到另一个类种,然后移除原类。

    应用场景:如果一个类不在承担足够的责任,不在有单独存在的理由(这通常是因为此前的重构动作移走了这个类的责任),此时就需要将这个萎缩类塞到其他的类中。

    示例:

    class Person...

      private String name;

      private Telephone telephone;

    class Telephone...

      private String areaCode;

      private String number;

      String getTelephoneNumber()...

    重构为:

    class Person...

      private String name;

      private String areaCode;

      private String number;

      String getTelephoneNumber()...

    5. Hide Delegate(隐藏“委托关系”)

    在服务类上建立客户所有的所有函数,用以隐藏委托关系。

    应用场景:这个核心思想就是封装。如果某个客户调用了建立与服务对象某个值域基础之上的函数,那么客户就必须维护这层关系,一旦这层委托关系发生变化,比如此服务对象的值域有变化,那么客户也要去响应这个变化才能继续使用原来的函数。我们可以在服务端防止一个简单的委托函数,将这层委托关系隐藏起来,从而去除这个一寸性。这样即使将来委托关系发生变化,变化会被限定在服务端,客户不会受到影响。

    示例:

    class Client...

      void func1() {

        Person p = new Person();

        String manager = p.getDepartment().getManager();

    class Person...

      Department getDepartment();

    class Department...

      String getManager();

    重构为:

      void func1() {

        Person p = new Person();

        String manager = p.getManager();

    class Person...

      Department getDepartment();

      String getManager() {

        return getDepartment().getManager();

      }    

    class Department...

      String getManager();

    6. Remove Middle Man (移除中间人)

    让客户直接调用委托类。

    应用场景:与 第5条Hide Delegate(隐藏“委托关系”)正好相反,隐藏“委托关系”的代价是每当客户要使用受委托类的新特性时,就必须在服务端添加一个简单的委托函数,随着特性越来越多,带来的代价不断攀升。所以两种方法存在一个折中的关系,说不上绝对要使用哪一种,结合实际情况合理决策。

    示例:

      void func1() {

        Person p = new Person();

        String manager = p.getManager();

    class Person...

      Department getDepartment();

      String getManager() {

        return getDepartment().getManager();

      }    

    class Department...

      String getManager();

    重构为:

    class Client...

      void func1() {

        Person p = new Person();

        String manager = p.getDepartment().getManager();

    class Person...

      Department getDepartment();

    class Department...

      String getManager();

    7. Introduce Foreign Method(引入外加函数)

    在client class中建立一个函数,兵役一个server class实体作为第一引数。

    应用场景:当我们正在使用一个类,它为我们提供了想要的所有服务,突然有一天,我们需要一个新功能,但是这个类无法提供,如果可以修改源码,那么万事大吉,否则我们就只能在调用的地方去补齐我们的功能。如果只使用一次这个功能,那么额外编码工作没什么大不了,然后如果需要多次使用这个函数,就得不断重复这些代码。重复代码是软件万恶之源,这些重复代码应该被抽出来放进同一个函数中。进行本项重构时,如果以外加函数实现一项功能,那就是一个明确信号:这个函数原本应该在提供服务的类中加以实现。如果需要大量外加函数,那么这种方法就不建议使用了。外加函数终归是权宜之计,如果有可能,应该把这些函数放到他们的理想家园。

    示例:

    Date newStart = new Date(previousEnd.getYear(), previousEnd.getMonth(), previousEnd.getDate()+1);

    重构为:

    Date newStart = nextDay(previousEnd);

    private static Date nextDay(Date date) {

      return new Date(date.getYear(), date.getMonth(), date.getDate()+1);

    8. Introduce Local Extension(引入本地扩展)

    建立一个新class,使它包含这些额外函数。让这个扩展品成为source class的subclass(子类)或wrapper(外覆类)。

    应用场景:类的作者无法预知未来,他们提供的函数可能不够用,如果我们可以修改源码,那么就可以很容易的增加或者修改已有类来满足使用;或者我们调用的地方少,增加的函数少时,可以使用第7条(Introduce Foreign Method(引入外加函数))来满足诉求。为了解决这个问题,我们需要将这些函数组织到一起,放到一个恰当的地方,此时,标准对象技术subclassing和wrapping是不错的选择。两种方法做选择时,首选subclass,这样的工作量比较少。

    subclass或wrapper示例:

    class SubDate extends Date {

      ....

    class DateWrapper {

      private Date _date;

    }

  • 相关阅读:
    Spring Session Logout
    VC6.0 error LNK2001: unresolved external symbol _main解决办法
    JDBC数据库编程基本流程
    JDBC连接SQL Server2008
    JDK的下载、安装及环境变量的配置
    奇数阶幻方口诀
    ping: sendto: Network is unreachable
    new/delete和malloc/free的区别
    MFC的消息管理
    VC++之自定义消息
  • 原文地址:https://www.cnblogs.com/youknowzcm/p/11729337.html
Copyright © 2020-2023  润新知