设计模式:多用组合少用继承原则解决继承层次过深问题

79 阅读2分钟

一、继承的问题

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(); // 委托下蛋实现类对象去实现下蛋通用代码
         ...//企鹅下蛋的特定代码
      }

}

以上就是,通过接口支持多态,通过组合实现类对象,委托实现类对象实现方法,达成代码的复用。

三、继承和组合的运用时机

如果类之间继承结构稳定,层次浅,关系不复杂,使用继承,反之用组合。