在对象之间搬移特性

0. 本章内容导图

在对象之间搬移特性_第1张图片
在对象之间搬移特性

1. 重构手法

1.1 搬移函数

概要:
你的程序中,有个函数与其所驻类之外的另一个类进行更多交流:调用后者,或被后者调用。
在该函数最常引用的类中建立一个有着类似行为的新函数。将旧函数变成一个单纯的委托函数,或是将旧函数完全移除。
动机:
a. 去除依恋情结或狎昵关系,将函数搬移到它应该呆的类中去
示例:
重构前:

class A {
    public void method();
}

class B {
}

重构后:

class A {
}

class B {
    public void method();
}

总结:
    是否需要搬移函数,往往不是一件容易决定的事,要经常浏览类中的所有函数,及时发现,在做决定时,可以跳出类本身,从它的客户的角度来审视一下接口所在的位置是否合适。

1.2 搬移字段

概要:
你的程序中,某个字段被其所驻类之外的另一个类更多地用到。
在目标类新建一个字段,修改源字段的所有用户,令它们改用新字段。
动机:
a. 去除类之间因字段而产生的狎昵关系
示例:
重构前:

class A {
    private K aField;
}

class B {
}

重构后:

class A {
}

class B {
    private K aField;
}

总结:
    在整个开发和维护的过程中,需求和功能会不断地发生变更,你的认识也会逐渐地加深,需要对原来的设计进行修改是常有的事,若这个过程中发现因某个类的字段而使得它与另一个类过于亲密,就要考虑是否需要将字段搬移到更适合它呆的地方。

1.3 提炼类

概要:
某个类做了应该有两个类做的事。
建立一个新类,将相关的字段和函数从旧类搬移到新类。
动机:
a. 保持类职责单一
b. 子类化不具通用特征的某些特性
总结:
    当业务变更,需要给某些类添加一些新责任时,往往会觉得不值得新建一个类来承担这些新的责任,久而久之,某些类的职责就变得不再单一,重构时,需要提炼类,分离相关职责。
    随着开发的进行,会发现某些类有需要子类化的需求,就需要分解原来的类,将某些特性以子类化的方式来处理。

1.4 将类内联化

概要:
某个类没有做太多事情。
将这个类的所有特性搬移到另一个类中,然后移除原类。
动机:
a. 每个类都需要维护,某个类不再承担足够责任,就没有继续存在的价值
总结:
    很多时候,随着重构的进行,会发现某些类承担的责任被逐渐搬移到其他类中,它们自身承担的责任越来越少,以至于到最后已不再有单独存在的理由了,就需要将剩余的特性搬移到相关的其他类中,然后移除该类。

1.5 隐藏“委托关系”

概要:
客户通过一个委托类来调用另一个对象。
在服务类上建立客户所需的所有函数,用以隐藏委托关系。
动机:
a. 去除不必要的中间人依赖
示例:
重构前:

class Person {
    private Department mDepartment;

    public  Department getDepartment() {
        return mDepartment;
    }
}

class Department {
    private Person mManager;

    public Person getManager() {
        return mManager;
    }
}

class Client {
    private Person mClient;

    // 代码中某处需要获得mClient的Manager
    mClient.getDepartment().getManager();
}

重构后:

class Person {
    private Department mDepartment;

    public  Department getDepartment() {
        return mDepartment;
    }

    // 直接实现客户需要的接口,没必要让客户通过委托去实现
    public Person getManager() {
        return mDepartment.getManager();
    }
}

class Department {
    private Person mManager;

    public Person getManager() {
        return mManager;
    }
}

class Client {
    private Person mClient;

    // 直接获得Manager,如何获得对客户是隐藏的,用户也不关心
    mClient.getManager();
}

总结:
    如果客户需要先通过服务对象的字段得到另一个对象,然后再调用后者的函数,客户就必须要知晓这一层的委托关系,一旦这层关系发生变化,客户也得跟着发生变化才行。实际上,站在客户的角度而言,只是想以一种最简单的方式完成调用,具体如何实现它是不关心的,也不应该过多关心,服务类的接口设计,就是为了满足客户的这种需求的。

1.6 移除中间人

概要:
某个类做了过多的简单委托动作。
让客户直接调用受托类。
动机:
a. 委托也是有代价的,如果服务类除了简单的委托,没有其他存在的价值,就应该移除这层委托。
总结:
    是否需要移除这层委托需要根据服务类承担的具体责任来做判断,代理模式就是通过委托达成某些目的的。

1.7 引入外加函数

概要:
你需要为提供服务的类增加一个函数,但你无法修改这个类。
在客户类中建立一个函数,并以第一参数形式传入一个服务类实例。
动机:
a. 扩展服务类的某个功能(服务类你无法通过源码修改)
示例:
重构前:

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

重构后:

Date newStart = nextDay(previousEnd);

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

总结:
    很多时候,你使用的三方sdk提供的功能可能无法满足实际的个别需求,但你又无法修改这部分代码,就可以通过引入外加函数来扩展sdk的功能。

1.8 引入本地扩展

概要:
你需要为服务类提供一些额外函数,但你无法修改这个类。
建立一个新类,使它包含这些额外函数。让这个扩展品成为源类的子类或包装类。
动机:
a. 较大范围扩展无法修改的服务类的功能
总结:
    同引入外加函数手法一样,这个重构手法也是为了扩展服务类的功能,不同的是,引入外加函数时往往需要扩展的功能只有个别函数;当需要扩展的功能比较多时,就需要通过引入本地扩展来实现了。实现手法是新建一个扩展类,将它作为服务类的子类或者包装类。

你可能感兴趣的:(在对象之间搬移特性)