组合和继承
继承带来的问题
在 《面向对象以及特性分析》文章,我们可以看到继承带来的问题:
- 菱形问题;
- 继承层次过深过复杂。
如上图所示,因为每个鸟根据特性会有会飞或者不会飞的特性,也会有会叫不会叫的特性等等,如果根据这些特性来设计类,然后让对应的终点类来继承的话,那么则会造成类的膨胀,从而代码变得十分的复杂。
组合的优势
针对上述继承所带来的问题,我们可以通过组合、委托、接口 3个技术手段,来进行另一种层面上的实现,具体代码如下。
// ================================ 接口定义 ==============================================
public interface Flyable{
void fly();
}
public interface Tweetable{
void tweet();
}
public interface EggLayable{
void layEgg();
}
// ================================ 委托类(通过在委托类中定义具体的代码实现,从而使用 组合 的形式来消除重复代码,做到复用) ==============================================
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 layEgg(){
// 具体实现
}
}
// ============================== 具体类 ================================================
public class Ostrich implements Tweetable,EggLayable{
// 组合上层实现
private TweetAbility tweetAbility = new TweetAbility();
private EggLayAbility eggLayAbility = new EggLayAbility();
// 通过组合,就不需要编写重复代码
@Override
public void tweet(){.
tweetAbility.tweet();
}
@Override
public void layEgg(){
eggLayAbility.layEgg();
}
}
public class Sparrow 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();
}
}
使用时机
根据上面的分析,可能觉得既然继承有那么多的问题,那干脆就不要用了吧,全都用组合多好。
其实不是这样的,继承和组合都各自有其代表的语义。
- 继承代表的是 is-A 关系,代表子类是父类的一种特殊情况;
- 组合代表的是 has-A 关系,代表的是被组合的类是父类的一部分;
此外继承还用简单易理解的方式,实现了代码的复用,因此如果逻辑比较简单,还是可以使用继承的。具体使用方式就需要开发人员根据具体情况具体分析了。
公众号截图
文章在公众号「iceWang」第一手更新,有兴趣的朋友可以关注公众号,第一时间看到笔者分享的各项知识点,谢谢!笔芯!