Replace Subclass with Fields (以字段取代子类)

Summary 你的各个子类的惟一差异只在“返回常量数据”的函数身上。修改这些函数,使它们返回超类中的某个(新增)字段,而后销毁子类。                                               java

Motivation: 创建子类的目的,是为了增长新特性或变化其行为。有一种变化行为被称为“常量函数”(constant method),它们会返回一个硬编码的值。这东西有其用途:你可让不一样的子类中的同一个访问函数返回不一样的值。你能够在超类中将访问函数声明为抽象函数,并在不一样的子类中让它返回不一样的值。函数

尽管常量函数有其用途,但若子类中只有常量函数,实在没有足够的存在价值。你能够在超类中设计一个与常量函数返回值相应的子弹,从而彻底去除这样的子类。如此一来就能够避免因继承而带来的额外复杂性。测试

Mechanics:编码

1. 对全部子类使用Replace Constructor with Factory Method.spa

2. 若是有任何代码直接引用子类,令它改而引用超类。设计

3. 针对每一个常量函数,在超类中声明一个final字段code

4.为超类声明一个protected构造函数,用以初始化这些新增字段。对象

5. 新建或修改子类构造函数,使它调用超类的新增构造函数。继承

6.编译,测试。get

7.在超类中实现全部常量函数,令它们返回相应字段值,而后将该函数从子类中删掉

8.没删除一个常量函数,编译并测试。

9.子类中全部的常量函数都被删除后,使用Inline Method将子类构造函数内联到超类的工厂函数中。

10.编译,测试。

11. 将子类删掉。

12. 编译,测试

13. 重复“内联构造函数、删除子类”过程,知道全部子类都被删除。

    范例:

   本例之中,咱们以Person表示“人”,并针对每种性别创建一个子类:以Male子类表示“男人”,以Female子类表示“女人”:    

abstract class Person{
    abstract boolean isMale();
    abstract char getCode();
    ...
    
    class Male extends Person{
        boolean isMale(){
            return true;
        }
        
        char getCode(){
            return "M";
        }
    }
    
    class Female extends Person{
        boolean isMale(){
            return false;
        }
        
        char getCode(){
            return "F";
        }
    }
}

在这里,两个子类之间惟一的区别就是:它们以不一样的方式实现了Person所声明的抽象函数getCode(),返回不一样的硬编码常量(因此getCode()是个长啦ing函数)。咱们应该将这两个子类去掉。

首先须要使用Replace Constructor with Factory Method。在这里,咱们须要为每一个子类创建一个工厂函数:

class Person...
    static Person createMale(){
        return new Male();
    }
    
    static Person createFemal(){
        return new Female();
    }

而后把对象建立过程从如下这样:

Person kent = new Male();

改成这样:

Person kent = Person.createMale();

将全部调用构造函数的地方都修改成调用工厂函数以后,就不该该再有任何对子类的直接引用了。一次全文搜索就能够帮助咱们证明这一点。而后,咱们能够把这两个子类都声明为private,这样编译器就能够帮助咱们,保证至少包外不会有任何代码使用它们。

如今,针对每一个常量函数,在超类中声明一个对应的字段:

class Person ...
    private final boolean _isMale;
    private fianl char _code;

而后为超类加上一个protected构造函数:

class Person ...
    protected Person(boolean isMale, char code){
        _isMale = isMale;
        _code = code;
    }

 再为子类加上新构造函数,令它调用超类新增的构造函数:

class Male ...
    Male(){
        super(true, 'M');
    }
class Female ...
    Female(){
        supre(false, 'F');
    }

完成这一步后,编译并测试。全部字段都被建立出来并被赋予初值,但到目前为止,咱们尚未使用它们。如今咱们能够在超类中加入访问这些字段的函数,并删掉子类中的常量函数,从而让这些字段登场:

class Person ...
    boolean isMale(){
        return _isMale;
    }

咱们能够逐一对每一个字段、每一个子类进行这一步骤的的修改,也能够采起一次性所有修改的手段。

全部字段都处理完毕后,全部子类也都空空如也了,因而能够删除Person中那个抽象函数的abstract修饰符,并以Inline Method将子类构造函数内联到超类的工厂函数中:

calss Pserson ...
    static Person createMale(){
        return new Person(true, 'M');
    }

编译,测试后,就能够删掉Male类,并对Female类重复上述过程。

相关文章
相关标签/搜索