继承的弊端
继承是面向对象的四大特性之一,用来表示类之间的is-a关系,可以解决代码复用的问题。虽然继承有诸多作用,但继承层次过深、过复杂,也会影响到代码的可维护性。所以,对于是否应该在项目中使用继承,网上有很多争议。很多人觉得继承是一种反模式,应该尽量少用,甚至不用。为什么会有这样的争议?我们通过一个例子来解释一下。
假设我们要设计一个关于鸟的类。我们将“鸟类”这样一个抽象的事物概念,定义为一个抽象类AbstractBird。所有更细分的鸟,比如麻雀、鸽子、乌鸦等,都继承这个抽象类。
我们知道,大部分鸟都会飞,那我们可不可以在AbstractBird抽象类中,定义一个fly()方法呢?答案是否定的。尽管大部分鸟都会飞,但也有特例,比如鸵鸟就不会飞。鸵鸟继承具有fly()方法的父类,那鸵鸟就具有“飞”这样的行为,这显然不符合我们对现实世界中事物的认识。当然,你可能会说,我在鸵鸟这个子类中重写(override)fly()方法,让它抛出UnSupportedMethodException异常不就可以了吗?具体的代码实现如下所示:
publicclassAbstractBird{//...省略其他属性和方法...publicvoidfly(){//...}}publicclassOstrichextendsAbstractBird{//鸵鸟//...省略其他属性和方法...publicvoidfly(){thrownewUnSupportedMethodException("Icantfly.");}}
publicinterfaceFlyable{voidfly();}publicinterfaceTweetable{voidtweet();}publicinterfaceEggLayable{voidlayEgg();}publicclassOstrichimplementsTweetable,EggLayable{//鸵鸟//...省略其他属性和方法...
Overridepublicvoidtweet(){//...}OverridepublicvoidlayEgg(){//...}}publicclassSparrowimpelentsFlayable,Tweetable,EggLayable{//麻雀//...省略其他属性和方法...Overridepublicvoidfly(){//...}Overridepublicvoidtweet(){//...}OverridepublicvoidlayEgg(){//...}}还有一些特殊的场景要求我们必须使用继承。如果你不能改变一个函数的入参类型,而入参又非接口,为了支持多态,只能采用继承来实现。
除此之外,还有一些设计模式会固定使用继承或者组合。比如,装饰者模式(decoratorpattern)、策略模式(strategypattern)、组合模式(