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

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

100834_gqxi_134516.png

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

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

Mechanics:

1. 对所有子类使用Replace Constructor with Factory Method.

2. 如果有任何代码直接引用子类,令它改而引用超类。

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

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

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

6.编译,测试。

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类重复上述过程。

转载于:https://my.oschina.net/u/134516/blog/212672

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值