一般情况下,继承(主要是由类实现)可能比组合(主要是由接口实现)更好实现,而且继承似乎有种一劳永逸的牛叉功能。这篇随笔是我读过一篇文章之后的一些想法,欢迎各位指教讨论。
一般情况下,我们总是花许多时间在系统的维护和变化上,有时会比开发花的时间更多,所以我们应该致力于提高可维护性和可扩展性上的复用程度,而继承在这方面可能略逊于组合,当然也有特殊情况。。。
使用组合建立的系统具有很大的弹性,不仅可以将算法族封装成类,更可以在运行时动态地改变行为,只要组合的行为对象符合正确的接口标准即可。
下面用一些代码来具体说说。。。还是用中的例子。
public abstract class Cat { IEatBehavior pEatBehavior; // 为行为接口定义一个引用变量 public void Eat() { pEatBehavior.Eat(); } public void Drink() { System.Out.Println(" I Drink Water."); } } public class WhiteCat Extends Cat { public WhiteCat() { pEatBehavior = new WhiteCatEatBehaviorClass(); // WhiteCatEatBehaviorClass 是实现接口 IEatBehavior 的一个具体类, // 里面的细节可以不用管, // 你只需要知道这是白猫特有的吃法就行了 } }
现在白猫也有自己 不同于 超类中的喝,如果使用继承的话,只要覆盖超类中的方法Drink()即可,但想一想,如果有很多子类继承该超类呢,那就得一个一个的覆盖,这可是体力活了。。。所以觉得在这使用组合可能更合适一点,现在就干起来,首先来新建一个含有Drink()方法的接口和一些具体类。
public interface IDrinkBehavior { public Drink(); } public class WhiteCatDrinkBehavior implements IDrinkBehavior { public void Drink() { System.Out.Println(" I Drink Soup."); } }
下面让我们再重新写一下超类及它的子类
public abstract class Cat { IEatBehavior pEatBehavior; // 为吃行为接口定义一个引用变量 IDrinkBehavior pDrinkBehavior; // 为喝行为接口定义一个引用变量,有了这个变量,原来的Drink()方法就可以简化了 public void Eat() { pEatBehavior.Eat(); } public void Drink() { pDrinkBehavior.Drink(); // 直接委托给 pDrinkBehavior 对象办就可以了 } } public class WhiteCat Extends Cat { public WhiteCat() { pEatBehavior = new WhiteCatEatBehaviorClass(); pDrinkBehavior = new WhiteCatDrinkBehaviorClass(); // 实例化一下,指明 喝 这个行为委托给哪个具体类来执行 } }
上面提到了可以在运行时动态地改变行为,这里也介绍一下实现方法,我们可以在超类中,加入两个方法:
public abstract class Cat{ // 之前的方法,变量不变 // 添加的方法 public Void SetEatBehavior(IEatBehavior pNewEatBehavior) { pEatBehavior = pNewEatBehavior; } public Void SetDrinkBehavior(IDrinkBehavior pNewDrinkBehavior) { pDrinkBehavior = pNewDrinkBehavior; }}
这样就可以在运行时调用SetEatBehavior,SetDrinkBehavior方法动态地改变行为了(组合的一大优点)。一般情况下,对象的 多种不同行为 适合 组合 来组织,而 静态的状态,类型等 适合 继承 来组织(这只是一家之说,仅参考)。。。