从面向对象设计谈接口和抽象类的异同

本文探讨了Java和C#中接口与抽象类的区别,重点分析了何时使用接口,何时使用抽象类。通过具体例子说明了类的单一职责原则及依赖倒置原则的应用。
 

    java和c#都不支持类的多继承,相对c++来说,又都增加了接口的概念,一个类可以实现多个接口;和c++一样,java和c#保留了抽象类的概念。在编码中很多情况下接口和抽象类可以互换,并且都能正确编译和运行,GOF23种设计模式在不同的书籍上也出现了接口和抽象类混用的情况。从语言层面讲,把接口看成是仅包含抽象属性和抽象方法的抽象类,勉强可以说得过去。所以很多程序员分不清什么时候该用接口,什么时候该用抽象类,只好任选其一。

    首先,java和c#不支持类的多继承是很有道理的(类的单一职责原则),当你在设计时遇到必须用多继承的情景时,请检查你的类结构设计是否合理,或者把某些父类改成接口。

    其次,接口中声明的成员方法不能有任何实现,这样如果两个类实现这个接口,有可能两个类需要编写同样的实现。而用抽象类则可以把实现写在抽象的父类中。

    以上两点仅仅是语言层面上的区别,是显而易见的。如果做到良好的面向对象设计,把类和类关系定的合理,可能根本遇不到上述两种情况。我们来看一个场景:

    固定翼飞机、军用固定翼飞机、民用固定翼飞机(民航客机)、孙悟空、海鸥

    军用固定翼飞机、民用固定翼飞机,都属于固定翼飞机,有强烈的 is a 关系,所以应该从固定翼飞机继承;如果一架飞机是固定翼飞机,那么它不可能仅仅是固定翼飞机,因为它不是民用就是军用,所以固定翼飞机是抽象的,不会有它本身的实例,有的只是它子类的实例。所以固定翼飞机是 abstract class 。

    上述五类事物都会飞,但显然,飞机、鸟、会飞的人完全不是一回事,不应该让它们继承于一个抽象的AbstractFly类,所以固定翼飞机、孙悟空、海鸥都可以实现IFly接口,却不能从同一个抽象类继承。孙悟空实现了IFly接口,同时还可以和猪八戒等实现IChangeSelf(会变)接口。

    一个类可以实现多个接口,接口是没有实际意义的,所以即使一个类实现了再多接口,它还可以不违反类的单一职责原则。反之,继承于多个抽象类,大多会违反类的单一职责原则,要不然就是那几个抽象类设计的不合理。

    另外,根据依赖倒置原则,当高层模块和底层模块不得不耦合时,最好由高层模块定义一个“规范”,让低层模块来实现,而不是高层模块直接调用低层模块的类和成员方法。“规范”在很多时候用接口和抽象类都可以编译和运行,但通过前文的例子,我们很容易知道这时应该用接口,因为高层模块仅仅是定义了一个规范,没有实际意义,而且高层模块并不了解低层模块的类结构,不该强行为低层模块设置父类,影响低层模块实现的灵活性。

接口抽象类的区别 抽象方法是必须实现的方法。就象动物都要呼吸。但是鱼用鳃呼吸,猪用肺呼吸。 动物类要有呼吸方法。怎么呼吸就是子类的事了。 现在有很多讨论建议提倡用interface代替abstract类,两者从理论上可以做一般性的混用,但是在实际应用中,他们还是有一定区别的。抽象类一般作为公共的父类为子类的扩展提供基础,这里的扩展包括了属性上行为上的。而接口一般来说不考虑属性,只考虑方法,使得子类可以自由的填补或者扩展接口所定义的方法,就像JAVA王子所说的事件中的适配器就是一个很好的应用。 用一个简单的例子,比如说一个教师,我们把它作为一个抽象类,有自己的属性,比如说年龄,教育程度,教师编号等等,而教师也是分很多种类的,我们就可以继承教师类而扩展特有的种类属性,而普遍属性已经直接继承了下来。 而接口呢~还是拿教师做例子,教师的行为很多,除了普通人相同的以外,还有职业相关的行为,比如改考卷,讲课等等,我们把这些行为定义成无body的方法,作为一个集合,它是一个interface。而教师张三李四的各自行为特点又有不同,那么他们就可以扩展自己的行为body。从这点意义上来说,interface偏重于行为。 总之,在许多情况下,接口确实可以代替抽象类,如果你不需要刻意表达属性上的继承的话。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值