接口 与抽象类的区别
那么在面向对象程序中应该说对封装还有一层新的定义,即将类的描述抽象化,也就是说描述类的外貌而不去考虑它的实际。
那么我们回过头来看抽象类,它必须被继承使用,描述的其实是一种继承关系,即"is a"的关系。类继承它,也就是说类拥有它所有抽象方法等,那么也就是类遵循了它所定义的规范。但是呢,这种规范是通过继承而来,类的发展必须依赖它的父类。
abstract class 工作
{
}
class 张三 : 工作{
}
abstract class 工作
{
}
class 人: 工作{
}
class 李四 : 人{
}
我们从这个例子中不难看出,张三和李四同样都遵循抽象工作的规范,都拥有上班这个方法,但是呢,他们的发展始终受到父类的影响。
当然,我这里只是从它们使用的角度来看,我们还能从他们设计角度度来看。上面我们虽然实现了人.上班()的过程,但是,这却违反了面向对象设计中的一个核心原则ISP(Interface Segregation Priciple),我们把李四的作为人的行为和他工作的行为混在一起。
那我们再来看看接口(interface),引用航天奇侠兄的一句话,接口,就是一个类的函数规范。 一个类 “继承”一个接口,等于说这个类必须提供接口所要求的所有函数。但是呢他们是一种实现关系,虽然在C#里我们还叫它为继承接口,但实际它是一种"like a"的关系。
interface 工作
{
public void 上班();
}
class 张三 : 工作{
}
interface 工作
{
public void 上班();
}
class 人 {
}
class 李四 : 人,工作{
}
interface 工作
{
public void 上班();
}
class 动物 {
}
class 人 : 动物 {
}
class 王五 : 人,工作{
}
此时我们来看,张三和李四同样遵循着interface工作所定义的规范,但是呢,他们(类)的发展并不受到父类的影响,张三、李四、王五都可以自由的发展自身类,具备有很高的自由度,我们再来从面向对象设计角度看,李四、王五继承人(因为他本质就是人),实现了工作。
应该说,接口的使用面比抽象类更广一些,而抽象类呢比接口更具限制性,体现的是继承关系。
当类的发展不需要受到限制和约束时,我们可以使用接口,此类可以自由的发展,此时继承接口的这个类它就是一个稳定的类,这也体现了接口保持类的稳定性。
这两者具备有很大的相似性,都源直面向对象思想,在使用何时抽象类,何时接口并没有一个定论,应该根据自己程序的大小,设计的方式,程序发展的空间来看,这就需要大家自己斟酌了。
接下来先说说抽象类和接口的区别。
区别一,两者表达的概念不一样。抽象类是一类事物的高度聚合,那么对于继承抽象类的子类来说,对于抽象类来说,属于“是”的关系;而接口是定义行为规范,因此对于实现接口的子类来说,相对于接口来说,是“行为需要按照接口来完成”。这些听起来有些虚,举个例子。例如,狗是对于所有狗类动物的统称,京哈是狗,牧羊犬是狗,那么狗的一般特性,都会在京哈,牧羊犬中找到,那么狗相对于京哈和牧羊犬来说,就属于这类事物的抽象类型;而对于“叫”这个动作来说,狗可以叫,鸟也可以叫。很明显,前者相当于所说的是抽象类,而后者指的就是接口。
区别二,抽象类在定义类型方法的时候,可以给出方法的实现部分,也可以不给出;而对于接口来说,其中所定义的方法都不能给出实现部分。
例如:
区别三,继承类对于两者所涉及方法的实现是不同的。继承类对于抽象类所定义的抽象方法,可以不用重写,也就是说,可以延用抽象类的方法;而对于接口类所定义的方法或者属性来说,在继承类中必须要给出相应的方法和属性实现。
区别四,在抽象类中,新增一个方法的话,继承类中可以不用作任何处理;而对于接口来说,则需要修改继承类,提供新定义的方法。
知道了两者的区别,再来说说,接口相对于抽象类的优势。
好处一,接口不光可以作用于引用类型,也可以作用于值类型。而抽象类来说,只能作用于引用类型。
好处二,.Net的类型继承只能是单继承的,也就是说一个类型只能继承一个类型,而可以继承多个接口。其实,我对于这一点也比较赞同,多继承会使继承树变的混乱。
好处三,由于接口只是定义属性和方法,而与真正实现的类型没有太大的关系,因此接口可以被多个类型重用。相对于此,抽象类与继承类的关系更紧密些。
好处四,通过接口,可以减少类型暴露的属性和方法,从而便于保护类型对象。当一个实现接口的类型,可能包含其他方法或者属性,但是方法返回的时候,可以返回接口对象,这样调用端,只能通过接口提供的方法或者属性,访问对象的相关元素,这样可以有效保护对象的其他元素。
好处五,减少值类型的拆箱操作。对于Struct定义的值类型数据,当存放集合当中,每当取出来,都需要进行拆箱操作,这时采用Struct+Interface结合的方法,从而降低拆箱操作。
参看如下文章提供的方法。
http://blog.csdn.net/Knight94/archive/2006/10/08/1326326.aspx
相对于抽象类来说,接口有这么多好处,但是接口有一个致命的弱点,就是接口所定义的方法和属性只能相对于继承它的类型(除非在继承类中修改接口定义的函数标示),那么对于多层继承关系的时候,光用接口就很难实现。因为如果让每个类型都去继承接口而进行实现的话,首先不说编写代码比较繁琐,有时候执行的结果还是错误,尤其当子类型对象隐式转换成基类对象进行访问的时候。
那么这时候,需要用接口结合虚方法来实现。参看IDisposable在继承类型中的实现方法。
http://blog.csdn.net/Knight94/archive/2006/10/10/1329214.aspx
其实在继承中,到底使用接口还是抽象类。接口是固定的,约定俗成的,因此在继承类中必须提供接口相应的方法和属性的实现。而对于抽象类来说,抽象类的定义方法的实现,贯穿整个继承树,因此其中方法的实现或者重写都是不确定的。因此相对而言,抽象类比接口更灵活一些。
如下给出两者的简单对比表格。
|
|
接口 |
抽象类 |
|
多继承 |
支持 |
不支持 |
|
类型限制 |
没有 |
有,只能是引用类型 |
|
方法实现 |
继承类型中必须给出方法实现 |
继承类中可以不给出 |
|
扩展性 |
比较麻烦 |
相对比较灵活 |
|
多层继承 |
比较麻烦,需要借助虚函数 |
比较灵活 |
总的来说,接口和抽象类是.Net为了更好的实现类型之间继承关系而提供的语言手段,而且两者有些相辅相成的关系。因此我并不强调用什么而不用什么,那么问题的关键在于,如何把这两种手段合理的应用到程序当中,这才是至关重要。


浙公网安备 33010602011771号