泰字的篆文演变:面向接口编程详解(一)——思想基础

来源:百度文库 编辑:偶看新闻 时间:2024/04/27 23:04:07

面向接口编程详解(一)——思想基础

本系列《面向接口编程详解》将分为三部分:
面向接口编程详解(一)——思想基础(已发布)
      在这一篇中,将对接口及面向接口编程有个大致的介绍,着重在于思想上的讲解。
面向接口编程详解(二)——编程实例(已发布)
      这一篇将结合一个实例“移动存储设备模拟”来让大家对面向接口编程有个直观印象。
面向接口编程详解(三)——模式研究(已发布)
      讲解几个设计模式中的面向接口思想和基于.NET平台的分层架构中的面向接口思想,加深理解。

      我想,对于各位使用面向对象编程语言的程序员来说,“接口”这个名词一定不陌生,但是不知各位有没有这样的疑惑:接口有什么用途?它和抽象类有什么区别?能不能用抽象类代替接口呢?而且,作为程序员,一定经常听到“面向接口编程”这个短语,那么它是什么意思?有什么思想内涵?和面向对象编程是什么关系?本文将一一解答这些疑问。

1.面向接口编程和面向对象编程是什么关系
      首先,面向接口编程和面向对象编程并不是平级的,它并不是比面向对象编程更先进的一种独立的编程思想,而是附属于面向对象思想体系,属于其一部分。或者说,它是面向对象编程体系中的思想精髓之一。

2.接口的本质
      接口,在表面上是由几个没有主体代码的方法定义组成的集合体,有唯一的名称,可以被类或其他接口所实现(或者也可以说继承)。它在形式上可能是如下的样子:

interface InterfaceName
{
    void Method1();
    void Method2(int para1);
    void Method3(string para2,string para3);
}


      那么,接口的本质是什么呢?或者说接口存在的意义是什么。我认为可以从以下两个视角考虑:
      1)接口是一组规则的集合,它规定了实现本接口的类或接口必须拥有的一组规则。体现了自然界“如果你是……则必须能……”的理念。
      例如,在自然界中,人都能吃饭,即“如果你是人,则必须能吃饭”。那么模拟到计算机程序中,就应该有一个IPerson(习惯上,接口名由“I”开头)接口,并有一个方法叫Eat(),然后我们规定,每一个表示“人”的类,必须实现IPerson接口,这就模拟了自然界“如果你是人,则必须能吃饭”这条规则。
      从这里,我想各位也能看到些许面向对象思想的东西。面向对象思想的核心之一,就是模拟真实世界,把真实世界中的事物抽象成类,整个程序靠各个类的实例互相通信、互相协作完成系统功能,这非常符合真实世界的运行状况,也是面向对象思想的精髓。
      2)接口是在一定粒度视图上同类事物的抽象表示。注意这里我强调了在一定粒度视图上,因为“同类事物”这个概念是相对的,它因为粒度视图不同而不同。
      例如,在我的眼里,我是一个人,和一头猪有本质区别,我可以接受我和我同学是同类这个说法,但绝不能接受我和一头猪是同类。但是,如果在一个动物学家眼里,我和猪应该是同类,因为我们都是动物,他可以认为“人”和“猪”都实现了IAnimal这个接口,而他在研究动物行为时,不会把我和猪分开对待,而会从“动物”这个较大的粒度上研究,但他会认为我和一棵树有本质区别。
      现在换了一个遗传学家,情况又不同了,因为生物都能遗传,所以在他眼里,我不仅和猪没区别,和一只蚊子、一个细菌、一颗树、一个蘑菇乃至一个SARS病毒都没什么区别,因为他会认为我们都实现了IDescendable这个接口(注:descend vi. 遗传),即我们都是可遗传的东西,他不会分别研究我们,而会将所有生物作为同类进行研究,在他眼里没有人和病毒之分,只有可遗传的物质和不可遗传的物质。但至少,我和一块石头还是有区别的。
      可不幸的事情发生了,某日,地球上出现了一位伟大的人,他叫列宁,他在熟读马克思、恩格斯的辩证唯物主义思想巨著后,颇有心得,于是他下了一个著名的定义:所谓物质,就是能被意识所反映的客观实在。至此,我和一块石头、一丝空气、一条成语和传输手机信号的电磁场已经没什么区别了,因为在列宁的眼里,我们都是可以被意识所反映的客观实在。如果列宁是一名程序员,他会这么说:所谓物质,就是所有同时实现了“IReflectabe”和“IEsse”两个接口的类所生成的实例。(注:reflect v. 反映  esse n. 客观实在)
      也许你会觉得我上面的例子像在瞎掰,但是,这正是接口得以存在的意义。面向对象思想和核心之一叫做多态性,什么叫多态性?说白了就是在某个粒度视图层面上对同类事物不加区别的对待而统一处理。而之所以敢这样做,就是因为有接口的存在。像那个遗传学家,他明白所有生物都实现了IDescendable接口,那只要是生物,一定有Descend()这个方法,于是他就可以统一研究,而不至于分别研究每一种生物而最终累死。
      可能这里还不能给你一个关于接口本质和作用的直观印象。那么在后文的例子和对几个设计模式的解析中,你将会更直观体验到接口的内涵。

3.面向接口编程综述
      通过上文,我想大家对接口和接口的思想内涵有了一个了解,那么什么是面向接口编程呢?我个人的定义是:在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类。
      这样做的好处是显而易见的,首先对系统灵活性大有好处。当下层需要改变时,只要接口及接口功能不变,则上层不用做任何修改。甚至可以在不改动上层代码时将下层整个替换掉,就像我们将一个WD的60G硬盘换成一个希捷的160G的硬盘,计算机其他地方不用做任何改动,而是把原硬盘拔下来、新硬盘插上就行了,因为计算机其他部分不依赖具体硬盘,而只依赖一个IDE接口,只要硬盘实现了这个接口,就可以替换上去。从这里看,程序中的接口和现实中的接口极为相似,所以我一直认为,接口(interface)这个词用的真是神似!
      使用接口的另一个好处就是不同部件或层次的开发人员可以并行开工,就像造硬盘的不用等造CPU的,也不用等造显示器的,只要接口一致,设计合理,完全可以并行进行开发,从而提高效率。

      本篇文章先到这里。最后我想再啰嗦一句:面向对象的精髓是模拟现实,这也可以说是我这篇文章的灵魂。所以,多从现实中思考面向对象的东西,对提高系统分析设计能力大有脾益。
      下篇文章,我将用一个实例来展示接口编程的基本方法。
      而第三篇,我将解析经典设计模式中的一些面向接口编程思想,并解析一下.NET分层架构中的面向接口思想。

对本文的补充:
      仔细看了各位的回复,非常高兴能和大家一起讨论技术问题。感谢给出肯定的朋友,也要感谢提出意见和质疑的朋友,这促使我更深入思考一些东西,希望能借此进步。在这里我想补充一些东西,以讨论一些回复中比较集中的问题。

1.关于“面向接口编程”中的“接口”与具体面向对象语言中“接口”两个词
      看到有朋友提出“面向接口编程”中的“接口”二字应该比单纯编程语言中的interface范围更大。我经过思考,觉得很有道理。这里我写的确实不太合理。我想,面向对象语言中的“接口”是指具体的一种代码结构,例如C#中用interface关键字定义的接口。而“面向接口编程”中的“接口”可以说是一种从软件架构的角度、从一个更抽象的层面上指那种用于隐藏具体底层类和实现多态性的结构部件。从这个意义上说,如果定义一个抽象类,并且目的是为了实现多态,那么我认为把这个抽象类也称为“接口”是合理的。但是用抽象类实现多态合理不合理?在下面第二条讨论。
      概括来说,我觉得两个“接口”的概念既相互区别又相互联系。“面向接口编程”中的接口是一种思想层面的用于实现多态性、提高软件灵活性和可维护性的架构部件,而具体语言中的“接口”是将这种思想中的部件具体实施到代码里的手段。

2.关于抽象类与接口
      看到回复中这是讨论的比较激烈的一个问题。很抱歉我考虑不周没有在文章中讨论这个问题。我个人对这个问题的理解如下:
      如果单从具体代码来看,对这两个概念很容易模糊,甚至觉得接口就是多余的,因为单从具体功能来看,除多重继承外(C#,Java中),抽象类似乎完全能取代接口。但是,难道接口的存在是为了实现多重继承?当然不是。我认为,抽象类和接口的区别在于使用动机。使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性。所以,如果你在为某个地方该使用接口还是抽象类而犹豫不决时,那么可以想想你的动机是什么。
      看到有朋友对IPerson这个接口的质疑,我个人的理解是,IPerson这个接口该不该定义,关键看具体应用中是怎么个情况。如果我们的项目中有Women和Man,都继承Person,而且Women和Man绝大多数方法都相同,只有一个方法DoSomethingInWC()不同(例子比较粗俗,各位见谅),那么当然定义一个AbstractPerson抽象类比较合理,因为它可以把其他所有方法都包含进去,子类只定义DoSomethingInWC(),大大减少了重复代码量。
      但是,如果我们程序中的Women和Man两个类基本没有共同代码,而且有一个PersonHandle类需要实例化他们,并且不希望知道他们是男是女,而只需把他们当作人看待,并实现多态,那么定义成接口就有必要了。
      总而言之,接口与抽象类的区别主要在于使用的动机,而不在于其本身。而一个东西该定义成抽象类还是接口,要根据具体环境的上下文决定。
      再者,我认为接口和抽象类的另一个区别在于,抽象类和它的子类之间应该是一般和特殊的关系,而接口仅仅是它的子类应该实现的一组规则。(当然,有时也可能存在一般与特殊的关系,但我们使用接口的目的不在这里)如,交通工具定义成抽象类,汽车、飞机、轮船定义成子类,是可以接受的,因为汽车、飞机、轮船都是一种特殊的交通工具。再譬如Icomparable接口,它只是说,实现这个接口的类必须要可以进行比较,这是一条规则。如果Car这个类实现了Icomparable,只是说,我们的Car中有一个方法可以对两个Car的实例进行比较,可能是比哪辆车更贵,也可能比哪辆车更大,这都无所谓,但我们不能说“汽车是一种特殊的可以比较”,这在文法上都不通。

作者:T2噬菌体
出处:http://leoo2sk.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

 

Tag标签: 面向接口,思想,软件工程,接口,面向对象posted @ 2008-04-10 12:23 EricZhang(T2噬菌体) 阅读(9761) 评论(101)  编辑 收藏 网摘 所属分类: 面向对象技术
发表评论  回复  引用  查看     #1楼 2008-04-10 12:31 | 李涛       好,支持一下。

  回复  引用     #2楼 2008-04-10 12:35 | yx_1 [未注册用户] 写得不错
  回复  引用  查看     #3楼 2008-04-10 12:39 | bmrxntfj       好文

在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类。

如果能考虑到依赖倒置,就更好了。应该说“客户持有接口”,这也是TDD的真正精髓。
  回复  引用  查看     #4楼 2008-04-10 12:46 | 杨连国       挺好,期待你的下文
  回复  引用  查看     #5楼 2008-04-10 12:46 | 专研.NET       期待下文
  回复  引用  查看     #6楼 2008-04-10 13:00 | 江大鱼       接口的使用直接反映了开发者面向对象开发的功底!
  回复  引用  查看     #7楼 2008-04-10 13:13 | Shinn       在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类。


這句話明顯不符合依賴倒置原則,接口應該是屬于調用者(客戶)的,既我需要這個接口的功能,被調用者(功能供應者)要提供服務就必須繼承這個接口。
  回复  引用  查看     #8楼 2008-04-10 13:15 | works guo       期待
  回复  引用     #9楼 2008-04-10 13:18 | lrr_ecer [未注册用户] 文章都写成这样了,还讲什么呢?
顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶

  回复  引用  查看     #10楼 2008-04-10 13:19 | Jim~       能理解,就好比电脑插槽可以插不同公司的内存条一样~~~
但是要真正做到面向接口编程,感觉不容易。。。
期待下一篇 :)
  回复  引用  查看     #11楼 [楼主]2008-04-10 13:22 | T2噬菌体       @Shinn
嗯,关于依赖倒置原则,我理解的还不是很透彻,所以还是使用比较原始的向下依赖,没有提及依赖倒置的问题。这样做,一方面也是为了初学者能更好理解一点。

依赖倒置是一个很重要的思想,我一定要加深在这方面的认识。

  回复  引用  查看     #12楼 2008-04-10 13:24 | Tony Zhou       @Shinn
不大同意你的说法
  回复  引用  查看     #13楼 2008-04-10 13:27 | 南院那       一下子对接口熟悉起来,真好. 期待下文!!!
  回复  引用  查看     #14楼 2008-04-10 13:43 | 白发先生       好,继续
  回复  引用  查看     #15楼 2008-04-10 13:46 | Alex wu       @T2噬菌体
老外就喜欢搞一大堆概念,什么依赖倒置,你要是不理解还真被这名字给吓着了。
依赖倒置是相对于结构化编程说的,结构化编程的时候,上层总是依赖于下层。

依赖倒置的意思是,我们在面向对象设计时,将这个上层依赖下层的结构化编程依赖思想倒置一下子(其实不是倒置,应该是转换一下子),变成:上层不依赖于下层,下层也不依赖于上层,上层和下层都依赖一组接口。这也就是说面向接口编程。
DIP的定义如下:
高层模块不依赖底层模块,两者都依赖抽象
抽象不应该依赖于细节,细节应该依赖于抽象(废话?还是我没正确理解?)

你的文章说的我都知道,但我写不出这么好的文章,赞一个!

  回复  引用  查看     #16楼 2008-04-10 14:00 | 小Q       有意思
学习
  回复  引用  查看     #17楼 2008-04-10 14:11 | 侯垒       好文.期待下文.
  回复  引用  查看     #18楼 2008-04-10 14:19 | 冰雪无情       等待下文啊 呵呵 正想多了解了解呢
  回复  引用  查看     #19楼 2008-04-10 14:38 | 生鱼片       支持下
  回复  引用  查看     #20楼 2008-04-10 15:02 | gsoft       感觉符合个人的口味,有时候看那些概念性的东西特别是那些翻译的专有名词一见就不知道怎么回事了。
  回复  引用  查看     #21楼 2008-04-10 15:14 | 凯锐       其實如果樓主三篇文章一并發出,連成一氣,必將引起如<<悟透JavaScript>>的效果!
不錯,支持下。
  回复  引用  查看     #22楼 2008-04-10 15:24 | 陈旭85       支持,收藏先
  回复  引用  查看     #23楼 2008-04-10 16:20 | BigRain       在楼主的陈述中,好象有两个地方不对:
1 面向接口编程中的接口并非面向对象语言中的interface.
2 面向接口编程 包含(>) 面向对象编程

  回复  引用     #24楼 2008-04-10 17:34 | guest [未注册用户] @BigRain

我认为面向接口编程中的“接口”应该包含面向对象语言中的接口及抽象类的。
  回复  引用  查看     #25楼 2008-04-10 18:03 | StillWartersRunDeep       呵呵
不错
  回复  引用  查看     #26楼 2008-04-10 18:08 | ygchina       能否在之后的文章中讲解一下接口与抽象类的区别
  回复  引用  查看     #27楼 2008-04-10 18:13 | SZW       很生动,期待下文:)
  回复  引用  查看     #28楼 2008-04-10 18:29 | PerfectDesign       非常不赞同楼主的看法。

  回复  引用  查看     #29楼 2008-04-10 18:37 | PerfectDesign       我认为楼主与我对接口和抽象类的认识有很大的偏差。
首先从楼主具的例子入手:
Iperson接口。那这样的接口是不是要实现吃饭睡觉上班心跳等方法呢?
这样的接口实现是不是有接口污染之嫌呢?
接口的设计一向是以专一和纯洁性为原则的。
相仿,这个例子我觉得用抽象类是再恰当不过了。
Person的抽象类,抽象的吃饭等方法,每个人有自己的各自实现,而抽象类Person又实现了对某一类事物的封装抽象。
而接口来说,你可以看看.net framework的设计原则:
IAccessible 接口
IFormattable
IList
IEnumerable
等都是标识的接口能够实现某种事情。实现了某接口的,都是“我能××”,表示我能干某件事情。
同时非常认同你的IReflectabe这个接口设计。
  回复  引用  查看     #30楼 2008-04-10 18:40 | PerfectDesign       抽象类和接口都是抽象一些类型,但是抽象类都是对某些事物的共同抽象,包括方法和属性等,他们标识的都是某些事物。
但是接口中只能定义规则,其实就是对被继承类型的标识,标识这些类型都能够干某件事情。
比如实现Icompare接口,表示这个类能够用作比较。

  回复  引用  查看     #31楼 2008-04-10 18:42 | PerfectDesign       行为的抽象,是规则,接口,
事物的抽象,是共性,是抽象类。

资历还很浅,只希望与楼主探讨探讨。
  回复  引用  查看     #32楼 2008-04-10 18:44 | BigRain       @guest
我认为面向对象中的接口(抽象)是一种义务,是一种规则.

面向接口编程的接口可以是一个类,一个方法,对于使用者来说,任何隐藏实现细节的都可以被看作接口.
  回复  引用  查看     #33楼 2008-04-10 18:48 | 朝晖的.net       "如果你是人,则必须能吃饭"
感觉好多问题,不能完全领悟面向接口,希望赶紧写完2,3,让我再体会一下,如果那时还不明了,我就要提问了。
  回复  引用     #34楼 2008-04-10 18:49 | snowwolflibo [未注册用户] 不才对这些纯概念性的东西不是很了解,但从多年OO编程的经验来看,
如果纯粹从结构上考虑,是不应该存在抽象类的,它的存在完全是出于编码的方便,因为有了抽象类,子类的很多方法就不用再实现了
  回复  引用     #35楼 2008-04-10 19:00 | snowwolflibo [未注册用户] 接口是为了实现"多态"
而抽象类是为了实现"复用"

这两者都是OO的基本思想

个人认为,面向接口编程应该属于OOP的一个子集

因为除了"多态",OOP还解决了"复用","解耦","内聚"等问题
  回复  引用  查看     #36楼 2008-04-10 19:04 | PerfectDesign       抽象类也能实现堕胎
  回复  引用     #37楼 2008-04-10 19:06 | snowwolflibo [未注册用户] 再说一句,之所以有接口的存在,是因为存在相应的处理类(有时也可能只是一段处理代码).
比如说"人",之所以要抽象出IPerson,是因为我们的业务里有一段逻辑要把"人"把做人看,也就是说存在一个类似于PersonHandler的类.
如果,我们的系统并不关注"人"做为"人"特性,那就不会有IPerson.

楼主关于猪啊/艾滋的例子很好很强大
  回复  引用  查看     #38楼 2008-04-10 19:06 | PerfectDesign       抽象类能复用是因为他是对事物的抽象
  回复  引用  查看     #39楼 2008-04-10 20:05 | 渔民       好文!期待下文
  回复  引用     #40楼 2008-04-10 21:13 | raid数据恢复 [未注册用户] 不是很明白!
  回复  引用     #41楼 2008-04-10 22:11 | macless [未注册用户] 不错.
  回复  引用  查看     #42楼 2008-04-10 23:24 | TT.Net       我认为,抽象类和接口的区别在于使用动机。使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性。
这句理解我很认同~
  回复  引用  查看     #43楼 2008-04-10 23:35 | Leem       很好,很强大.期待下文
  回复  引用  查看     #44楼 2008-04-10 23:50 | ZH-CN       接口比抽象更抽象
  回复  引用     #45楼 2008-04-11 08:47 | bai [未注册用户] 强烈期待博主的下文,写的真是精辟极了
  回复  引用  查看     #46楼 2008-04-11 08:55 | Wenly       期待下文
  回复  引用     #47楼 2008-04-11 09:22 | 路人A [未注册用户] 不错,写的非常好啊,
特别是经过#29与楼主的阐述,让我初步知道接口与抽象类的区别..
接口:是继承该接口所必须遵循的规则,
抽象类:是提取出所有继承该抽象类的共性,从而达到节省代码,重用的功能,

本人是.NET刚入门,不知道我讲的对不对。
  回复  引用     #48楼 2008-04-11 10:05 | NingDev [未注册用户] 个人理解:
接口:更多的是对外提供服务。
抽象:则是对内提供服务。
期待下文,谢谢楼主。
  回复  引用     #49楼 2008-04-11 10:40 | zdleek [未注册用户] --引用--------------------------------------------------
李涛: 好,支持一下。

--------------------------------------------------------

  回复  引用  查看     #50楼 2008-04-11 11:53 | 杨子       --引用--------------------------------------------------
bmrxntfj: 好文

在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类。

如果能考虑到依赖倒置,就更好了。应该说“客户持有接口”,这也是TDD的真正精髓。
--------------------------------------------------------

  回复  引用  查看     #51楼 2008-04-11 12:02 | 杨子       顶顶顶顶

楼主赶快出下文
终于明白点 面向接口编程的意思了。。。

  回复  引用     #52楼 2008-04-11 15:30 | jack_web [未注册用户] 好文!
  回复  引用     #53楼 2008-04-11 16:08 | bamboo_ding [未注册用户] 通俗易懂,比那些个高谈阔论的家伙们可强多了,很多人写人文章并不是告诉新手怎么理解,而是告诉别人我懂的很多......
  回复  引用     #54楼 2008-04-11 16:16 | AaronLu [未注册用户] 楼主,你不写书中国程序员就亏大了!(写Blog也行,哈哈)
很佩服楼主的清晰、缜密、明了的思维。对于一个技术人员(窃以为楼主是)来说,能有如此文笔功力的确令人刮目。望眼欲穿期待楼主更加精彩的下文。

拜读此文后,我也有一点感想:

1 对于“粒度”的阐述
楼主在这里对这个感念的解释十分精辟。第一次看到这个词,心中疑惑不已,本以为文中只是一笔带过,但是接下来的阐释令我茅塞顿开。看这段文字的时候有“行云流水”般酣畅之感。

2 关于“interface” 和 “abstract class”
下面是个人对这两个概念的理解:
interface:定义一组特定的行为。任何实现此interface的class都必须提供这些行为的实现(多态性)。它强调的是“行为”:只要某个类实现了此interface,就相当于订立了一个“行为契约”。

abstract class:定义一组公共的特征(行为或者数据),有一部分特征需要派生类去实现(多态性),一般是abstract method或者virtual method。它强调的是派生关系:只要某个类实现了此abstract class,就相当于订立了一个“is a”的契约。

对楼主所说的:
=====
我认为,抽象类和接口的区别在于使用动机。
=====
个人有些不同的想法(不是抠字眼,是想探求问题的本质)。结构(定义或者组成)决定性质,性质决定用途。interface” 和 “abstract class”这两个概念最根本的区别在于它们的“结构”,而楼主所说的区别应该是这种“结构区别”在用途上的一种表现。只要透彻理解这个根本区别,那么在具体使用场景中做出选择应该不是一件困难的事情。

谢谢!
  回复  引用  查看     #55楼 [楼主]2008-04-11 16:24 | T2噬菌体       @AaronLu
--引用--------------------------------------------------

个人有些不同的想法(不是抠字眼,是想探求问题的本质)。结构(定义或者组成)决定性质,性质决定用途。interface” 和 “abstract class”这两个概念最根本的区别在于它们的“结构”,而楼主所说的区别应该是这种“结构区别”在用途上的一种表现。只要透彻理解这个根本区别,那么在具体使用场景中做出选择应该不是一件困难的事情。
--------------------------------------------------------

恩……我觉得很有道理。interface本身就不允许定义方法体和属性,这就从结构上限制我们不可能用接口实现代码复用。而抽象类的结构完全可以实现代码复用。不知你是不是这个意思,呵呵。

  回复  引用  查看     #56楼 2008-04-12 09:00 | pomp       最近正在为接口这个概念的深层理解而头疼,此文正中,并且同时还明白了抽象类的意义,谢谢,期待续文
  回复  引用  查看     #57楼 2008-04-14 14:21 | andy65007       棒极了!
  回复  引用     #58楼 2008-04-17 11:41 | 夏文俊 [未注册用户] 写得很好撒```继续向下看~!
  回复  引用  查看     #59楼 2008-04-21 12:06 | jillzhang       我认为,抽象类和接口的区别在于使用动机。使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性
--------------------------------------------------------------
不太认同,说抽象类相比接口有利于代码复用是正确的,但说接口的目的是实现多态,至少在多态的层面上,接口与抽象类都有体现,抽象类的virual方法难道就不是多态么?所以说接口是多态,抽象类也是多态。从设计目的上来说,接口和抽象类,本身就具有者非常类似的目的。那就是都是想制定一套规则,将具体问题进行抽象,归纳。但接口与抽象类还是有一定区别:
1)二者不在一个层级
 抽象类可以实现接口,但接口却无法继承抽象类吧?所以严格来说,接口是抽 象类的上级。
2)作用域不同
接口体现了的是相同类别或者不同类别下事物的归纳,而抽象类则更多的体现在对相同类别事务的归纳上。这在编程中的体现就是一个类可以实现多个接口,而不能继承多个抽象类,因为一个人能有各种的功能,这些功能可能是人类特有的,也可能是和其他动物共有的,但绝对不能有一个以上的亲生父亲。
3)开放性有所不同
 接口和抽象类虽然相似,但在某些场合,如分布式开发中,接口就更受欢迎,特别是面向服务中,更关注的是能干什么?而相比之下,是什么不太重要。是骡子,是马,是头驴,反正能拉车就可以。所以我认为接口相比抽象类更开放一点,更适合互操作一点。

  回复  引用  查看     #60楼 2008-05-16 12:09 | Borg       学习了,对接口与抽象类有了更深层次的认识。
  回复  引用  查看     #61楼 2008-05-27 17:44 | 夜风777       很好的文章,对接口的概念更清晰了
  回复  引用  查看     #62楼 2008-06-05 11:35 | 辨色龙       思想来自于原则,原则产生思想
  回复  引用     #63楼 2008-06-13 12:37 | Vin [未注册用户] 我认为楼主对接口和抽象类的理解有点不很正确。59楼的阐述更为正确。
  回复  引用  查看     #64楼 [楼主]2008-06-16 09:44 | T2噬菌体       @Vin

恩,看了59楼朋友的解释,觉得他对接口和抽象类的解释更为合理!
  回复  引用  查看     #65楼 2008-06-16 14:21 | 求知无傲       不错。
  回复  引用  查看     #66楼 2008-06-17 13:43 | 长沙小能       关注你的,好好写
  回复  引用  查看     #67楼 2008-06-17 14:30 | 小庄       接口是用来抽象“服务类”的,抽象类是用来抽象“实体类”的;
楼主的那个硬盘的例子让我联想到电脑中的各个部件之间都是通过“接口”来实现的,什么USB,IDE,等,把硬盘进行抽象,抽象的结果肯定是个抽象类,因为硬盘是个“实体类”,要对硬盘和其他例如南桥芯片的通信方式进行抽象,抽象的结果肯定是个接口,因为通信是个“服务类”;
接口的功能并不一定用来向上层提供抽象调用,还可以和本层提供抽象调用,所以调用者并不一定是它的上层,这也是依赖注入的基础!

  回复  引用  查看     #68楼 2008-06-17 17:05 | sunbird69       写的很好
59楼 的阐述更为合理
认同接口比抽象类 更为开放
  回复  引用  查看     #69楼 2008-06-19 12:55 | 艺林       “可以被类或其他接口所实现(或者也可以说继承)”

这一句我觉得欠妥,子接口是不能实现父接口,只能继承。可以考虑改为:“可以被类或其他接口继承,并必须在继承它的类中得以实现”
  回复  引用  查看     #70楼 [楼主]2008-06-19 12:59 | T2噬菌体       @艺林

恩,你的说法更合理!

  回复  引用  查看     #71楼 2008-06-19 13:29 | 艺林       依赖倒置,个人感觉有点像制造行业里的体系认证。比如我是一家汽车主机厂(就是生产汽车整件的),我规定只有通过TS16949的汽车零部件公司才能成为我的零部件供应商(因为我相信通过了TS16949认证的公司才有能力提供符合我们要求的零部件)。作为零部件公司,为了给我供货,就必须认证TS16949体系。你说你有ISO9000认证,对不起,我不认,因为随便啥子公司都能认真ISO9000,这不能说明你的能力。
换个例子说,比如我是一个钻石王老五,我发布公告说我的择偶标准是,具有生小孩功能的人。于是所有想傍我的人都去培训深造以使自己具有生小孩的技能,以符合我的要求,从而可以成为我的配偶候选人。当然,我不必关心这些人是男人还是女人,管他什么人,只要是能生小孩的人,都可以参加海选!或者说,我只用你生小孩的功能,其它一概都不关心。
所以,某个类实现一个接口,就是对使用该接口的对象示好,说明我能为你提供服务。确切的说,对象不是在使用接口,而是通过接口公布自己对服务提供对象的能力的要求。从这个层面上说,接口就是一种契约。
有点偏题了,回过来。依赖倒置形象点理解,就是我需要什么,我把它定义成契约(接口),然后我的服务提供商履行契约。是先有需求,再由实现;先有市场,再有生产。这很重要,折射到软件设计中,就是先确定上层的需求,再设计下层的接口,以需求驱动实现,才能设计出是,而且刚刚是我想要的东西。
依赖倒置,体现客户才是上帝的意识,体现服务意识。
  回复  引用  查看     #72楼 2008-06-23 23:41 | Bēniaǒ       晚到的beniao学习了,留个记号。
传说看了文章后回帖是在珍惜别人的劳动成果。我也乱谈几句。

两者相同点(书上都是这么说的):
都不能被直接实例化,都可以通过继承实现其抽象方法。
都是面向抽象编程的技术基础,实现了诸多的设计模式。

不同点:
接口支持多继承;抽象类不能实现多继承。
接口只能定义抽象规则;抽象类既可以定义规则,还可能提供已实现的成员。
接口是一组行为规范;抽象类是一个不完全的类,着重族的概念。
接口可以用于支持回调;抽象类不能实现回调,因为继承不支持。
接口只包含方法、属性、索引器、事件的签名,但不能定义字段和包含实现的方法;抽象类可以定义字段、属性、包含有实现的方法。
接口可以作用于值类型和引用类型;抽象类只能作用于引用类型。例如,Struct就可以继承接口,而不能继承类。




  回复  引用     #73楼 2008-06-27 21:30 | guo_sky99 [未注册用户] 在面向接口编程时,虽然各各层次之间都依赖于接口,但是业务逻辑层的开发还是需要数据访问层来提供数据,这样才能测试业务逻辑层的正确性,但是如果数据访问还没有开发完成,那麽怎么进行业务逻辑层的开发呢?这不是还依赖吗?这怎么进行同时开工呀?


  回复  引用  查看     #74楼 [楼主]2008-06-28 17:01 | T2噬菌体       --引用--------------------------------------------------
guo_sky99: 在面向接口编程时,虽然各各层次之间都依赖于接口,但是业务逻辑层的开发还是需要数据访问层来提供数据,这样才能测试业务逻辑层的正确性,但是如果数据访问还没有开发完成,那麽怎么进行业务逻辑层的开发呢?这不是还依赖吗?这怎么进行同时开工呀?


--------------------------------------------------------
这个很简单,可以采用“欺骗数据”方法,例如,业务逻辑层要进行测试,而数据访问层没有写好,那么业务逻辑层的程序员就可以写一个假的数据访问层,它符合接口,但是根本不访问数据源,而只是返回一些虚拟的数据,这样可以测试业务逻辑层有没有完成指定的业务。

其实更好的方法是TDD

  回复  引用     #75楼 2008-06-29 22:52 | guo_sky99 [未注册用户] @T2噬菌体
--引用--------------------------------------------------
T2噬菌体: --引用--------------------------------------------------
guo_sky99: 在面向接口编程时,虽然各各层次之间都依赖于接口,但是业务逻辑层的开发还是需要数据访问层来提供数据,这样才能测试业务逻辑层的正确性,但是如果数据访问还没有开发完成,那麽怎么进行业务逻辑层的开发呢?这不是还依赖吗?这怎么进行同时开工呀?


--------------------------------------------------------
这个很简单,可以采用“欺骗数据”方法,例如,业务逻辑层要进行测试,而数据访问层没有写好,那么业务逻辑层的程序员就可以写一个假的数据访问层,它符合接口,但是根本不访问数据源,而只是返回一些虚拟的数据,这样可以测试业务逻辑层有没有完成指定的业务。

其实更好的方法是TDD

--------------------------------------------------------
谢谢楼主,明白了,采用“欺骗数据”方法这种方法不错,谢谢!
你说更好的方法是TDD,TDD是什么啊?
  回复  引用     #76楼 2008-07-05 19:25 | 419431086 [未注册用户] 面向对象的本质是模拟现实
这个观点欠妥!!
本来qq419431086
能否探讨一下!
  回复  引用     #77楼 2008-07-10 10:46 | greathwj [未注册用户] 真的不错,期待下一个到来
  回复  引用  查看     #78楼 2008-07-28 10:31 | 凤&杰¥天下       我感觉 这个人挺强。很有发展的前途啊! 理论+实践 正是我需要的了,在加上硕士生 这么好的文笔 真是 佩服 的我 不知道说些什么了。不会形容了......o(∩_∩)o...
  回复  引用  查看     #79楼 2008-07-28 10:34 | 凤&杰¥天下       对了 版主 希望你能加我 为你的博客好友 。 我好期待向你学习啊 我加了你的MSN 但是你好像经常不在线了。 先在这 说声 谢谢你呦! 我很期待呦!
  回复  引用  查看     #80楼 [楼主]2008-07-28 11:10 | T2噬菌体       @凤&杰¥天下

呵呵。我MSN不经常在,你可以加我QQ:47824761。
那个博客好友我不知道怎么加,要不你加我吧。^_^

  回复  引用  查看     #81楼 2008-09-08 09:21 | 水边       好像很多人都很赞同59楼的说法,
从面向对象的角度来理解 接口和抽象类

抽象类是定义一些共性的东西,凡是这个类别的都会有的属性和方法
比如人就应该是一个抽象类,人都有身高属性,获得身高的方法也是一致的,如果定义为接口,那么男人和女人都要重写一遍获得身高的方法,
这个不论是从代码利用,还是OO的理解上来说,都应该是抽象类
还有你说的吃饭做为接口并不合适,因为吃饭是一个共性的动作,是人就会吃饭,这个吃的方法应该是作为抽象方法,因为每个人吃饭的方法可能不同,有人吞着吃,有人咬着吃等等,所以就要继承人这个类的子类来具体实现。

而接口是定义一些特性的规则,也就是比较特殊的东西,比如有的人会跳舞,有的人会游泳
那么就应该定义一个跳舞的接口,一个游泳的接口
如果男人实现了跳舞的接口,那么这个男人就会跳舞了
但是并不是每个男人,或者每个人都会跳舞

楼上有一个人说的言简意赅:
行为的抽象,是规则,接口, (是特殊的个性)
事物的抽象,是共性,是抽象类(是一般的共性)
  回复  引用  查看     #82楼 2008-09-08 11:21 | 水边       如果只是为了代码复用,才用抽象类,
没有复用的情况,就用接口
根本就是背离OO。
抽象类和接口都是由于OO才引入的概念,

当然如果你程序中的Women和Man两个类基本没有共同代码,可以使用接口实现,可是你考虑到了扩展或者需求变更了情况吗?

如果你的项目一开始所有的需求都定型了,不会变化,而且也没有扩展的可能
那么你用什么都无所谓了
但是这可能吗?任何一个做过不少项目的都知道,需求的变更很常见,也许今天没有共同代码,明天一变,又有了,你是不是又要为了代码复用,去修改接口为抽象类,或者不改结构,在子类分别写相同的代码?

如果一开始就从OO的角度去设计,上面的问题很多都可以得到解决,再举一个例子吧:
比如门,有门锁这个属性(抽象的,因为门可以使用任何一种锁),但是锁门这个方法,就是简单一句话,
锁.Close();
所以这里门就应该设计为抽象类,
锁在目前这个需求里可以是一个抽象类,也可以是接口,实现Close方法。
但是如果考虑到扩展,比如锁,在以后会不会可能增加钥匙这个抽象属性,同时增加钥匙的Open()方法来开门呢?

  回复  引用     #83楼 2008-10-10 17:15 | Jak [未注册用户] 新手,虽然不能完全理解,但是这种类比风格非常不错,up下
  回复  引用  查看     #84楼 2008-10-25 20:12 | dispute       --引用--------------------------------------------------
水边: 好像很多人都很赞同59楼的说法,
从面向对象的角度来理解 接口和抽象类

抽象类是定义一些共性的东西,凡是这个类别的都会有的属性和方法
比如人就应该是一个抽象类,人都有身高属性,获得身高的方法也是一致的,如果定义为接口,那么男人和女人都要重写一遍获得身高的方法,
这个不论是从代码利用,还是OO的理解上来说,都应该是抽象类
还有你说的吃饭做为接口并不合适,因为吃饭是一个共性的动作,是人就会吃饭,这个吃的方法应该是作为抽象方法,因为每个人吃饭的方法可能不同,有人吞着吃,有人咬着吃等等,所以就要继承人这个类的子类来具体实现。

而接口是定义一些特性的规则,也就是比较特殊的东西,比如有的人会跳舞,有的人会游泳
那么就应该定义一个跳舞的接口,一个游泳的接口
如果男人实现了跳舞的接口,那么这个男人就会跳舞了
但是并不是每个男人,或者每个人都会跳舞

楼上有一个人说的言简意赅:
行为的抽象,是规则,接口, (是特殊的个性)
事物的抽象,是共性,是抽象类(是一般的共性)
--------------------------------------------------------
看了那么多,就81楼的最通俗易懂··
  回复  引用  查看     #85楼 2008-11-15 23:07 | 李胜攀       楼主的文章很好,知道一件事情和如何将它清晰的表达出来是完全不同的两件事情,楼主在这方面做得很好,值得我学习。
  回复  引用     #86楼 2008-12-18 15:14 | Michael-jan [未注册用户] 不错,看了很有体会,好好学习。
  回复  引用     #87楼 2008-12-27 11:39 | hxmupdata [未注册用户] 赞下楼主的贡献!好人啊~~~
对接口的浅薄理解(本人是程序员新手)
我的观点:不管他是加工食品还是新鲜食品还是其他的人造食品,只要这个食品
好吃,没危害,能添饱肚子,我就选择他,认可他。
所以我对于什么面向对象呀,面向过程呀,面向接口呀,我只要
观察到他的某一方面给我带来了,编程的便利,我就吸收。
所以我的学习方法是:拿来主义,只用最好的。
评价方法:只看进步的一面,只关注需要进步的一面。
{
先谈:面向对象和面向过程的联系和区别。
面向过程:我形容他是“小农经济”(自给自足)
他的贡献就是(1:结构
2:函数与变量)
面向对象:我形容他是“资本主义经济”(商业+资本)
他的贡献就是(1:组件
2:类)
注:自给自足的意思是 什么事情都要自己去干
(控制要自己干,消息的传达也要自己干,
具体怎么干还要自己动手,汗。完成一件事情可真够累的。。。。。)
而面向对象(商业:消息驱动。资本:功能划分。)我想干什么只要下达个命令,就能得到结果,过程不需要关心,多好。具体应该是资本注入,成立公司,招点人,得到商业消息,完成产品,消息完成,告诉投资者,然后资本撤出,公司倒闭,人员失业,消息清除。。。。。。}
本人编程经历太少,觉得掌握面向对象,已经很伟大了。。。。

看了楼主的面向接口才发现:革命尚未成功。中国虽然GDP很高了,但人均太少,仍然是发展中国家。。。。。

看完文章结合自己体会:接口,其实就是定义的消息通道。接口是消息的载体。
面向接口的意思是,整个程序的架构上,要以接口为核心。分析,设计的都要从接口的角度去做。
面向接口的好处:结构清晰,功能清晰,架构变的异常容易。可以在极短的时间内根据需求设计出多种多样的初级模型。架构师和顾客都会笑了。
结构的清晰带来了,团队项目时候的,更好的项目管理,由于面向接口,组建或模块相对独立,如果想维护都很方便。项目经理也会笑了。
程序员的任务更加明确。只要符合接口的要求,想怎么搞就怎么搞,几乎没有别的方面的要求。程序员也笑了。


  回复  引用     #88楼 2009-02-20 10:01 | 张晓敏 [未注册用户] 张洋,我是小敏啊,写得很好,对我很有启示,期待你的文章
  回复  引用  查看     #89楼 2009-03-03 11:16 | Rivers Zhao       难得的好文
  回复  引用     #90楼 2009-03-18 09:17 | bdbox1 [未注册用户] 对我真是太有用了,期待你的下一篇好文~
  回复  引用  查看     #91楼 2009-04-01 15:02 | 零始       师哥(同是烟大计算机学院的)写的很不错啊 学习了 以后经常向你学习啊
  回复  引用  查看     #92楼 2009-04-05 11:34 | 暴雨中的杀机       支持
  回复  引用     #93楼 2009-04-10 21:43 | J2 [未注册用户] "接口是一组规则的集合,它规定了实现本接口的类或接口必须拥有的一组规则。" 有个疑问,接口可以实现接口?

  回复  引用  查看     #94楼 [楼主]2009-04-11 01:10 | T2噬菌体       @J2
接口可以实现接口
  回复  引用  查看     #95楼 2009-04-19 21:44 | abruzzi       不错,这篇文章写的很有水平! 对面向对象的理解看来是很深的了,呵呵。
  回复  引用     #96楼 2009-06-04 13:02 | Jeffrey Hua [未注册用户] 总体来看,写的还可以.以下为个人看法:
1.不要乱用"思想""哲学""科学""体系"这些词
大致浏览了一些你写的一些文章,用到了很多这些词.对你使用这些词的意图可以理解,想从更高的层次探讨一下面向对象,试图用这些词来统一你的相关文章的背后的主线.但是这些词语外延太大,你的文章不足以支持这些high level的词语的含义,文章相反显得狠牵强和混乱.

2.对接口的理解还不够深入。文章中的IPerson绝对不是个好例子.接口的本质是描叙对象能做哪些事情,是一组职责的集合,是对对象的品质和能力的一种修饰.这也就是为什么现在Java和C#中的framework中对接口的命名更多的是形容词(少数是名词)的原因.PerfectDesign的意见不错.
"体现了自然界‘如果你是……则必须能……’的理念。"这里的省略号我只能从你里面的叙述中猜测,套用你的IPerson示例,容易让大家这么理解:“如果你是IPerson这个接口,则必须能eat。”

3.关于接口的阐述推荐以下2个连接,理解的更为深刻.
http://c2.com/cgi/wiki?InterfacesShouldBeAdjectives
http://alistair.cockburn.us/Using+natural+language+as+a+metaphoric+base+for+object-oriented+modeling+and+programming

  回复  引用  查看     #97楼 [楼主]2009-06-04 18:23 | EricZhang(T2噬菌体)       @Jeffrey Hua
多谢批评。我以后会注意某些方面。

其实,这篇文章是我刚接触面向接口时的文章,那时理解不够深刻,现在看确实有些幼稚。

至于"思想"、"哲学"、"科学"、"体系"这些词,请注意,我一般的题目都是“XXX的讨论”或“XXX的探讨”,所以,我虽然用了这些词,但并不是试图构建这么高深的论题,而只是进行这方面的探讨,但我又找不到合适的替代词。我想,一个学生如果试图构建"思想"、"哲学"、"科学"、"体系"那必然不妥,不过探讨或讨论应该没问题吧。