现在的位置: 首页 > 综合 > 正文

我所理解的接口和抽象类

2011年07月17日 ⁄ 综合 ⁄ 共 3285字 ⁄ 字号 评论关闭
 刚才闲着无聊逛论坛,然后看到了lin的文章接口VS抽象类,于是就写了这个文章,就当作为ASP.NET这个版块开个头,抛砖引玉吧。但是我的理解思想肯定没有lin,也没有各位那样深入,因此,希望大家可以不吝赐教,谢谢。如果我的文章污染了大家的眼球,小弟在这说抱歉了。

        首先,我来从最简单的语法层面来比较一下接口和抽象类。
        1.        先来说抽象类。毋庸置疑,抽象类也是个类,他同样继承于System.Object类,所不同的只是他比普通的类多了一个或多个抽象方法,使抽象类不能实例化罢了。
        2.        而接口。他也同样是一个类,我从以下两点证明这个事情,第一,从编译后的IL代码来看,接口也同样是以.class作为前缀的。第二,我们写一个接口,然后我们用接口一样可以直接调用Object类的静态方法Equal和ReferenceEqual方法。(但是有一点我一直没想明白,为什么接口编译后的IL没有显式地继承Object类呢?.class interface public abstract auto ansi ConsoleApplication2.IStudy)

        接下来,从应用的角度来剖析一下两者的不同。
        以前从书上看到过这样一种比较接口和抽象类的说法,说接口是来描述一些东西可以做什么,而抽象类是来描述一些东西是什么。用专业点的话来说,应该说接口是行为的抽象,而抽象类是类的抽象(不知道我这样概括是否准确)。
      我们也可以这样理解,抽象类是来概括出一些相似类的共同行为,而接口是来概括出一些无关类的共同行为。语言表达不清了,我用代码来说明这个问题:
    

Code

      我们来看这个例子,首先看抽象类的部分,实现鸭子这个抽象类的是两个类,GreenDuck和YellowDuck,这不用我多说,他们都是鸭子,这两个类是相联系的,于是他们便有一个公共的父类,也就是抽象类Duck。但是我们想,Superman和Duck,这两者之间我们可就想不出什么关系来了。超人不能结婚生出鸭子,鸭子也同样不能怀孕弄出个超人了。但是我们经过总结却可以看到,鸭子和超人都可以飞!所以我们便抽象出了这个IFly的接口,让超人和鸭子都去实现它。通过这个例子,我想大多数都可以更好的理解接口和抽象类了吧。接口是为无关的类定义一组行为,其实就是定义了一组契约。而抽象类是为一组具有公共特征的类提取出一个类来作为他们的父类。(有一个笑话说抽象类就是抽去出相像的类,仔细想想也不无道理)。
      然后,我们来分别讨论下接口和抽象类的应用之处。在此之前,再次声明,在下基本无项目经验,观点未查询资料,因此理解不足之处希望大家指出。
      先来说抽象类。个人认为抽象类是一种很简易的泛化,如果几个类的确可以明显抽取出一个父类,那我还是觉得用抽象类比较合适。现在网上有些观点说建议用接口彻底取代抽象类,我认为这是个很荒谬的说法。举一个小例子:我们要写一个程序,这个程序要对宇宙的各个星球都做出描述,这样,我们就要建上亿个类,分别来描述各个星球。现在,我们发现他们有两个共同点,第一,他们都在膨胀,第二,他们都在运动。我们有两种做法,第一种,就是说像网上有些人说的一样,把这两种做法分别实现为两个接口,public interface IRun和public interface IExtend,然后我们让这些星球分别实现这两个接口,但是突然有一天,我们发现这些星球其实都可以制造氧气,于是,根据接口的不变性原则,我们不得不增加一个接口public interface  CreateOx,然后把所有的类都更新一下,实现这个接口,然后写下相同的代码:Console.WriteLine(“生产氧气”);我们想想这是个多大的工程。但是如果我们使用抽象类就不一样了。我们只需要对抽象类做出更新即可,当然,这也违背了设计原则中的OCP(Open-Close-Principle)。因此,个人总结如下,使用抽象类是一个比较简易的抽象,或者说是比较粗糙的抽象,一处更新,处处更新,对于大量子类来说更易于修改(当然,这在一定程度上也是抽象类的一个缺点)。在应用中,比如说在组件设计上,我们可以预计到未来将有多个版本,那么我们不妨把一些公有的实现的功能和一些独特的功能封装到一个抽象类里,这样当更新新版本后便较容易修改,这主要利用的是抽象类中可以有已实现的方法,也可以有属性。举个例子,在.net中,有多个控件,比如Label,Textbox,他们都可以从工具箱拖动到设计界面上,那么这个时候,我们便可以把他们拖动的代码和一些他们所专有的方法封装成一个抽象类,然后让所有的控件来继承这个类,今后哪怕新加入了新控件,也可以直接来继承这个抽象类来完成他特有的操作,并且还可以拖动。
      对于接口,我想这个应用就比较广泛了。在设计模式中,接口的应用可谓是无处不在,应用接口,我们可以更好的做到OCP原则,另外,“针对接口编程而不是针对实现编程”“多用组合少用继承”,都是在说接口的重要性。接口将设计与实现相分离,设计者可以定义出接口,然后留给程序员来实现,我认为这是接口一个很好的方面。另外,在外观模式中,也鼓励我们把组件对外留出接口,然后我们把这些接口汇总成一个Fa?ade,对外提供这个类就可以了,这在我们常用的三层架构以及N层架构中有比较广泛的应用。对于接口,我就不再赘言了,接口的应用实在太广泛了。当然,对于接口的设计,我再提及一下,接口的设计是个比较有趣的事情。我们不能把接口设计得过大,这样不符合SRP(Single Responsibility Priciple)原则。但是过分的细化又会影响系统的运行效率。
      好了,只写这些了,希望大家多多指教。

 

抱歉!评论已关闭.