资源预览内容
第1页 / 共24页
第2页 / 共24页
第3页 / 共24页
第4页 / 共24页
第5页 / 共24页
第6页 / 共24页
第7页 / 共24页
第8页 / 共24页
第9页 / 共24页
第10页 / 共24页
亲,该文档总共24页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
面向接口编程1. 面向接口编程和面向对象编程是什么关系首先,面向接口编程和面向对象编程并不是平级的,它并不是比面向对象编 程更先进的一种独立的编程思想,而是附属于面向对象思想体系,属于其一部分。 或者说,它是面向对象编程体系中的思想精髓之一。2. 接口的本质接口,在表面上是由几个没有主体代码的方法定义组成的集合体,有唯一的 名称,可以被类或其他接口所实现(或者也可以说继承)。它在形式上可能是如下 的样子:interface InterfaceNamevoid 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的实例进行比较,可能是比哪辆 车更贵,也可能比哪辆车更大,这都无所谓,但我们不能说“汽车是一种特殊的可 以比较”,这在文法上都不通。问题的提出定义:现在我们要开发一个应用,模拟移动存储设备的读写,即计算机与 U 盘、MP3、移动硬盘等设备进行数据交换。上下文(环境):已知要实现U盘、MP3播放器、移动硬盘三种移动存储设 备,要求计算机能同这三种设备进行数据交换,并且以后可能会有新的第三方的移 动存储设备,所以计算机必须有扩展性,能与目前未知而以后可能会出现的存储设 备进行数据交换。各个存储设备间读、写的实现方法不同,U盘和移动硬盘只有这 两个方法,MP3Player还有一个PlayMusic方法。名词定义:数据交换=读,写看到上面的问题,我想各位脑子中一定有了不少想法,这是个很好解决的问 题,很多方案都能达到效果。下面,我列举几个典型的方案。解决方案列举方案一:分别定义 FlashDisk、MP3Player、MobileHardDisk 三个类,实现各自的Read和Write方法。然后在Computer类中实例化上述三个类,为每个类分别 写读、写方法。例如,为 FlashDisk 写 ReadFromFlashDisk、WriteToFlashDisk 两 个方法。总共六个方法。方案二:定义抽象类MobileStorage,在里面写虚方法Read和Write,三个 存储设备继承此抽象类,并重写Read和Write方法。Computer类中包含一个类型 为MobileStorage的成员变量,并为其编写get/set器,这样Computer中只需要 两个方法:ReadData和WriteData,并通过多态性实现不同移动设备的读写。方案三:与方案二基本相同,只是不定义抽象类,而是定义接口IMobileStorage,移动存储器类实现此接口。Computer中通过依赖接口 IMobileStorage 实现多态性。方案四:定义接口 I Readable和I Wri table,两个接口分别只包含Read和 Wri te,然后定义接口 IMob ileSt orage 接口继承自 I Readable 和 I Wri table,剩下 的实现与方案三相同。下面,我们来分析一下以上四种方案:首先,方案一最直白,实现起来最简单,但是它有一个致命的弱点:可扩展 性差。或者说,不符合“开放-关闭原则”(注:意为对扩展开放,对修改关 闭)。当将来有了第三方扩展移动存储设备时,必须对Computer进行修改。这就 如在一个真实的计算机上,为每一
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号