在平时开发中,有时会遇到这样一种情形:有一个类,他有很多行为,有的行为是固定的,有的行为又是可变的。这个时候,如何更好的封装呢?
一个类中分开变与不变的部分
比如:有一个类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类这一处即可,而不用向上面那样修改小明、小红等多处了
总结
这里的核心在于,首先得区分什么是多变的部分,什么又是不变的部分
将不变的部分使用继承以方便复用,
将多变的部分用组合来方便拓展