组合优于继承

在平时开发中,有时会遇到这样一种情形:有一个类,他有很多行为,有的行为是固定的,有的行为又是可变的。这个时候,如何更好的封装呢?

一个类中分开变与不变的部分

比如:有一个类Person,具有行为:说话、工作、睡觉、会死。其中,睡觉和死亡都是一样的,但是,不同的人会说不同的语言,做不同的工作

  • 小明 说普通话 工作是学生
  • 小红 说广东话 工作是学生
  • 赵信 说广东话 工作是战士
  • 盖伦 说英语 工作是战士

继承

定义抽象人类

/**
 * 抽象人类
 */
public abstract class Person {

    //说着不一样的语言
    public abstract void speak();

    //有着不同的工作
    public abstract void work();

    //都是一样的睡觉
    public void sleep() {
        System.out.println("他在睡觉");
    }

    //都是一样的会死
    public void die() {
        System.out.println("他死了");
    }

}

不同的人继承 该类,重写自己的speak和work方法

public class XiaoMing extends Person {

    @Override
    public void speak() {
        System.out.println("他说普通话");
    }

    @Override
    public void work() {
        System.out.println("他的工作是学生");
    }
}
package effetivejava.composite.ext;

/**
 * yutianran 2017/3/3 下午4:19
 */
public class XiaoHong extends Person {
    @Override
    public void speak() {
        System.out.println("他说广东话");
    }

    @Override
    public void work() {
        System.out.println("他的工作是学生");
    }

}

这种写法很简单直观,但是,弊端在于:如果学生的work方法需要调整,每一个学生(小明、小红)都需要修改自己的代码,没法统一修改。

那么,可不可以将这些动态可变的行为封装一下呢?

组合

抽象人类

public abstract class Person {

    private SpeakBehavior speakBehavior;

    private WorkBehavior workBehavior;

    public void setSpeakBehavior(SpeakBehavior speakBehavior) {
        this.speakBehavior = speakBehavior;
    }

    public void setWorkBehavior(WorkBehavior workBehavior) {
        this.workBehavior = workBehavior;
    }

    //说着不一样的语言
    public void speak() {
        speakBehavior.speak();
    }

    //有着不同的工作
    public void work() {
        workBehavior.work();
    }

    //都是一样的睡觉
    public void sleep() {
        System.out.println("他在睡觉");
    }

    //都是一样的会死
    public void die() {
        System.out.println("他死了");
    }

}

这里将speak、work都封装成一个类,然后让Person类持有SpeakBehavior和WorkBehavior,具体调用Person的方法时都自动转调相应Behavior的方法

行为 接口

public interface SpeakBehavior {
    void speak();
}

public interface WorkBehavior {
    void work();
}

实现相应的Behavior

public class Fighter implements WorkBehavior {
    @Override
    public void work() {
        System.out.println("他的工作是战士");
    }
}

public class Student implements WorkBehavior {
    @Override
    public void work() {
        System.out.println("他的工作是学生");
    }
}

public class Chinese implements SpeakBehavior {
    @Override
    public void speak() {
        System.out.println("他说普通话");
    }
}

public class Cantonese implements SpeakBehavior {
    @Override
    public void speak() {
        System.out.println("他说广东话");
    }
}

不同的人用法:

public class XiaoMing extends Person {

    public XiaoMing() {
        setSpeakBehavior(new Chinese());
        setWorkBehavior(new Student());
    }
}

优点

这样封装以后呢,以后学生的具体方法改了,只需要修改Student类这一处即可,而不用向上面那样修改小明、小红等多处了

总结

这里的核心在于,首先得区分什么是多变的部分,什么又是不变的部分

将不变的部分使用继承以方便复用,
将多变的部分用组合来方便拓展

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值