一、继承的问题
1、问题:
继承最大问题是,继承层次过深,继承关系过于复杂会影响到代码的可读性和可维护性。
2、案例:
比如鸟类按照是否会飞,是否会叫这两个维度划分,就会产生四种情况:会飞会叫,会飞不会叫,不会飞会叫,不会飞不会叫。这样就需要设计四个抽象类。
不仅仅这两个维度,还有从是否会下蛋,是否会迁徙,是否会潜水等更多维度区分的话,就会产生更多的抽象类,继承层次就会越来越深,继承关系就会越来越复杂。
二、组合相比继承的优势
1、组合优势
继承主要作用是支持多态,代码复用。
但是,继承层次过深,继承关系过于复杂会影响到代码的可读性和可维护性。
而支持多态可以通过接口达成,代码复用可以通过组合,委托来实现,从而解决继承的缺点问题。
2、组合案例:
定义三个接口:
public interface Flyable {
//飞行
void fly();
}
public interface Tweetable {
//鸟叫
void tweet();
}
public interface EggLayable {
//下蛋
void eggLay();
}
创建实现这三个类的实现类:
public class FlyAbility implements Flyable {
@Override
//所有鸟类实现飞行方法的共用代码
public void fly() { //... }
}
public class TweetAbility implements Tweetable {
@Override
//所有鸟类实现叫唤方法的共用代码
public void tweet() { //... }
}
public class EggLayAbility implements EggLayable {
@Override
//所有鸟类实现下蛋方法的共用代码
public void eggLay() { //... }
}
当创建某个具体鸟时,要实现飞行,鸟叫,下蛋方法。比如企鹅类(penguin),通过调用FlyAbility类对象fly方法,再加上企鹅飞行的特定代码,从而实现企鹅类飞行的方法。
public class Penguin implements Flyable,Tweetable, EggLayable {//企鹅类
private FlyAbility flyAbility = new FlyAbility(); //组合进飞行实现类对象
private TweetAbility tweetAbility = new TweetAbility(); //组合进鸟叫实现类对象
private EggLayAbility eggLayAbility = new EggLayAbility(); //组合进下蛋实现类对象
@Override
public void fly() {
flyAbility.fly(); // 委托飞行实现类对象去实现飞行通用代码
...//企鹅飞行的特定代码
}
@Override
public void tweet() {
tweetAbility.tweet(); // 委托鸟叫实现类对象去实现鸟叫通用代码
...//企鹅鸟叫的特定代码
}
@Override
public void layEgg() {
eggLayAbility.layEgg(); // 委托下蛋实现类对象去实现下蛋通用代码
...//企鹅下蛋的特定代码
}
}
以上就是,通过接口支持多态,通过组合实现类对象,委托实现类对象实现方法,达成代码的复用。
三、继承和组合的运用时机
如果类之间继承结构稳定,层次浅,关系不复杂,使用继承,反之用组合。