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

  1.面向接口编程和面向对象编程是什么关系

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

  2.接口的本质

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

  1. 以下是引用片段:
  2. interface InterfaceName{
  3.   void method1();
  4.   void method2(int para1);
  5.   void method3(string para2,string para3);
  6. }

  那么,接口的本质是什么呢?或者说接口存在的意义是什么。我认为可以从以下两个视角考虑:

  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的实例进行比较,可能是比哪辆车更贵,也可能比哪辆车更大,这都无所谓, 但我们不能说“汽车是一种特殊的可以比较”,这在文法上都不通。

转载于:https://blog.51cto.com/shaojun168/1060781

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

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

    我想,对于各位使用面向对象编程语言的程序员来说,"接口"这个名词一定不陌生,但是不知各位有没有这样的疑惑:接口有什么用途?它和抽象类有什么区别?能不能用抽象类代替接口呢?而且,作为 ...

  2. [转]面向接口编程详解(一)——思想基础

    我想,对于各位使用面向对象编程语言的程序员来说,"接口"这个名词一定不陌生,但是不知各位有没有这样的疑惑:接口有什么用途?它和抽象类有什么区别?能不能用抽象类代替接口呢?而且,作为 ...

  3. 面向接口编程详解(三)——模式研究

    通过前面两篇,我想各位朋友对"面向接口编程"的思想有了一定认识,并通过第二篇的例子,获得了一定的直观印象.但是,第二篇中的例子旨在展示面向接口编程的实现方法,比较简单,不能体现出面 ...

  4. 面向接口编程详解(三)

    通过前面两篇,我想各位朋友对"面向接口编程"的思想有了一定认识,并通过第二篇的例子,获得了一定的直观印象.但是,第二篇中的例子旨在展示面向接口编程的实现方法,比较简单,不能体现出面 ...

  5. java 开发详解_面向接口编程详解-Java篇

    相信看到这篇文字的人已经不需要了解什么是接口了,我就不再过多的做介绍了,直接步入正题,接口测试如何编写.那么在这一篇里,我们用一个例子,让各位对这个重要的编程思想有个直观的印象.为充分考虑到初学者,所 ...

  6. 面向接口编程详解(二)——编程实例

    作者: T2噬菌体  来源: 博客园  发布时间: 2012-06-09 12:13  阅读: 19178 次  推荐: 25   原文链接   [收藏]   通过上一篇文章的讨论,我想各位朋友对&q ...

  7. 面向接口编程详解——编程实例--(T2噬菌体)

    问题的提出 定义:现在我们要开发一个应用,模拟移动存储设备的读写,即计算机与U盘.MP3.移动硬盘等设备进行数据交换. 上下文(环境):已知要实现U盘.MP3播放器.移动硬盘三种移动存储设备,要求计算 ...

  8. Android Loader 异步加载详解一:基础概念

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/70241844 本文出自[赵彦军的博客] Android Loader 异步加载详解 ...

  9. python协程详解_python协程详解

    原博文 2019-10-25 10:07 − # python协程详解 ![python协程详解](https://pic2.zhimg.com/50/v2-9f3e2152b616e89fbad86 ...

最新文章

  1. python提高办公效率-提升Python程序运行效率的6个方法
  2. MySQL Group Replication调研剖析
  3. ORACLE包和过程依赖关系测试
  4. hadoop的idea连接配置_idea远程连接hadoop(macOS)
  5. 算法 --- 求两个集合的并集
  6. 均质机工作原理动画_3D动画演示:有刷直流电机的工作原理
  7. 【转贴】想应聘的瞧仔细了:HW分析大全
  8. LeetCode 302. 包含全部黑色像素的最小矩形(BFS)
  9. 力扣1. 两数之和(哈希表,JavaScript)
  10. gcc/g++ 的参数总结(二)
  11. Android中的文字占位符
  12. gps 数据解析-NMEA 0183协议
  13. python第三方库安装位置_python第三方库安装在哪
  14. Invalid MEX-file '/xxx/lk.mexa64': /xxx/anaconda3/lib/./libharfbuzz.so.0: undefined symbol: FT_Done_
  15. java中1字节(8位)_Java中基本数据类型占几个字节多少位
  16. 【项目实践】DCGAN绘制理想女朋友照片实践,从爬虫到生产女友
  17. 基于Android的网络聊天软件(仿QQ)设计与实现
  18. C语言自学笔记,第一天
  19. 免费电脑纯净绿色好用的软件
  20. C语言学习笔记[第11天]

热门文章

  1. system.err android.os.NetworkOnmainThreadException 错误解决办法
  2. C++ 文件大小格式化
  3. Android官方技术文档翻译——Gradle 插件用户指南(7)
  4. Node.Js 学习随笔2
  5. 微软的日历控件为什么从1753年开始?Sqlserver数据库不能插入1753年之前的数据?...
  6. 利用正则表达式去掉html代码
  7. 全景视频的跟踪与合成方法
  8. 【知识库专访】亲加CTO郝飞:直播技术架构解密与优化之道
  9. android:windowSoftInputMode属性
  10. JAVA操作MYSQL数据库