无锡春华教育:面向接口编程详解(三)——模式研究

来源:百度文库 编辑:中财网 时间:2024/04/30 18:14:32

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

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

      通过前面两篇,我想各位朋友对“面向接口编程”的思想有了一定认识,并通过第二篇的例子,获得了一定的直观印象。但是,第二篇中的例子旨在展示面向接口编程的实现方法,比较简单,不能体现出面向接口编程的优势和这种思想的内涵。那么,这一篇作为本系列的终结篇,将通过分析几个比较有深度的模式或架构,解析隐藏其背后的面向接口思想。这篇我将要分析的分别是MVC模式和.NET平台的分层架构。
      这篇的内容可能会比较抽象,望谅解。

1.从MVC开始
MVC简介:
      本文不打算详细解释MVC架构,而是把重点放在其中的面向接口思想上。所以在这里,只对MVC做一个简略的介绍。
      MVC是一种用于表示层设计的复合设计模式。M、V、C分别表示模型(Model)、View(视图)、Controller(控制器)。它们的职责如下:
      模型:用于存储应用中的数据及运行逻辑,是应用的实体。
      视图:负责可视部分,用于与用户交互及呈现数据。视图只负责显示,不负责将用户的操作行为解释给模型。
      控制器:负责将用户的行为解释给模型。根据指定的策略和用户的操作,调用模型的逻辑。

      关于三者的关系,我画了一张图,大家请看:


      它们之间的交互有以下几种:
      1.当用户在视图上做任何需要调用模型的操作时,它的请求将被控制器截获。
      2.控制器按照自身指定的策略,将用户行为翻译成模型操作,调用模型相应逻辑实现。
      3.控制器可能会在接到视图操作时,指定视图做某些改变。
      4.当模型的状态发生改变时,将通过某种方式通知视图。
      5.视图可以从模型获取状态,从而改变自己的显示。

      MVC介绍完了,那么可能会有人问,我们的主题呢?面向接口思想呢?其实,MVC中处处都存在面向接口的影子。下面,我对其中几个侧面进行解释。
      1.首先我们可以看到,视图和模型是有直接交互的,也就是上面的4、5两点。但是有一点可能会让你吃惊:它们两个谁也不“认识”谁,即它们相互并不知道对方是做什么的、有什么属性、有什么方法,但是它们能交互。这是怎么做到的呢?因为它们个各知道对方实现了某一个接口。
      此乃面向接口思想一大作用:使相互不认识的类进行交互。这样做是很有好处的,首先它们之间的耦合度大大降低,其次双方都可以进行替换,只要实现了相同的接口,就没有问题。
      打个不太恰当的比喻。我们都知道120这个电话号码,是急救电话。其实120就是个接口,因为当你拨打这个电话时,你不知道那边是哪所医院,甚至不知道那边是不是医院,你只知道电话那头的地方可以救人,也可以说实现了IHelp接口。这样,你通过一个号码可以说同全部的救人机构联系起来了,当有紧急事件,接线控制那边会将你的请求接到最近可用的机构,你就可以最快的得到帮助。
      现在我们假设没有使用面向接口思想,来看看会发生什么恐怖的事情:首先,我家的120号码是绑定在本市第一人民医院的,即当我拨打120时,只能拨通第一人民医院。如果有一天我食物中毒了,急忙拨通了120,但是电话那边告诉我他们医院的救护车都派出去了,我问那怎么接通别家医院的电话,那边的MM很温柔的告诉我,让我打电话给网通公司,然后重新为我布线。于是我吐血而亡……
      言归正传。这里,我要引入一个设计模式,叫观察着(Observer)模式。这个模式大约是这样的:整个模式中有两种实体:观察者和被观察者,它们分别实现一个接口,这里我们姑且叫做IObserver与IObserverSubject。IObserver只有一个方法,例如叫Update,当被观察者状态改变时,调用这个方法,用来通知观察者。IObserverSubject接口有两个方法,都是供观察者调用。一个用来将观察者注册为此被观察者的观察对象,另一个用于将观察者移除。
      一般情况下,一个被观察者对应多个观察者。
      在MVC中,视图是观察者,模型是被观察者,当模型状态改变时,调用所有观察者的Update方法,通知视图模型有变,视图在Update方法里写下响应代码,完成操作。通过这个方法,视图和模型就可以在仅依赖接口的情形下进行交互,而不必强耦合,而且在模型不变的情况下,视图可以随意替换。(只要实现了IObserver)

      2. 在MVC中另一个使用接口的地方就是控制器,这里我要首先引入一个设计模式:策略模式(Strategy)。在MVC中,控制器就使用了这个模式。
      刚才我说过,视图负责与用户交互,但是,它只负责界面显示部分,至于当用户做了某个操作(如单击某个按钮)后系统应该怎么反应,视图并不负责,它只是将这个动作交给控制器,控制器根据内置的策略,将用户操作翻译成模型的逻辑。这就是说,同一个视图、同一种操作,模型可以做出不同的反应,这取决与控制器的内置策略。所以,我们的系统中可以有很多控制器,它们有不同的策略,当视图希望改变策略时,它可以更换控制器。怎么实现呢?这就需要视图不能和具体控制器耦合,而是要仅依赖一个控制器接口(如IController),并聚合一个IController的实例。当希望更改策略时,可以在系统运行时动态更换Controller,这就是策略模式的实现。

      关于MVC的接口思想就先介绍到这里。其实MVC中还有很多地方用到面向接口,由于本文不是专门介绍MVC或设计模式的,所以对用到的模式没有做详解,而是把重点放在其中的面向接口思想上。如果没有设计模式的基础,读上文可能会有些困难,希望各位见谅!我打算在以后专门写文章来解析MVC。

2..NET平台下分层架构的面向接口思想
      我们知道,在做大一点的系统应用时(特别是B/S架构),比较好的方法是分层架构。所谓分层架构,是指将系统从职责上分成若干层,每层各司其职,上层依赖下层完成操作。
      在.NET平台上,比较经典的分层架构是三层架构,从下到上依次是:数据访问层、业务逻辑层、表示层。各层职责如下:
      数据访问层:负责与数据源交互,完成数据访问等一系列操作。
      业务逻辑层:完成与系统业务有关的逻辑操作。
      表示层:负责与用户交互、呈现数据等一切与系统表示有关的操作。

      刚才我们说过,分层架构下是向下依赖的(不考虑依赖倒置),也就是业务逻辑层要调用数据访问层完成与数据源有关的操作,而表示层调用业务逻辑层完成业务逻辑工作。但是,表示层对数据访问层是没有依赖的。
      在这个架构中,每一层都不是一个类,而是一个类族,例如,在一个CMS系统中,数据访问层可能会有一系列的类,分别负责用户、文章、评论等业务实体的数据访问操作,而业务逻辑层也一样。如果我们直接依赖,即业务逻辑层实例化数据访问层的类,表示层再实例化业务逻辑层的类,会造成强耦合。如果我想把数据库从SQLServer换成MySQL,则要改变整个业务逻辑层代码,这是个不好的设计。(还记得“开放-关闭”原则吗)所以,一般的做法是,为数据访问层和业务逻辑层分别定义一族接口,业务逻辑层不依赖具体的数据访问层,而是仅依赖数据访问层的接口族,表示层也一样,依赖业务逻辑层的接口族。如此一来,当要更换数据库时,我们就不必改写整个业务逻辑层,因为业务逻辑层里根本没有任何数据访问层中的具体类,而全是通过接口实现的。在.NET中,只要配合配置文件和反射机制,再运用Abstract Factory设计模式,就可以实现“依赖注入”,即在不改动代码的情况下根据配置选择相应的层次组件。这样,我们就可以为不通数据库分别实现数据访问层,也可以编写ORM的数据访问层,甚至是基于XML的,只要实现了数据访问层接口族,就可以和业务逻辑层无缝连接,从而极大提高了软件的灵活性和可维护性。当然要更改业务逻辑层也是一样。
      如果说,前面的例子都是从微观视角讨论接口,那么,这个例子则从宏观视角展现了面向接口编程的内涵和优势。很抱歉在这里不能对这个架构深入讲解,有兴趣的朋友可以参考微软的官方示例.NET PetShop4。(但是请注意,这个示例中业务逻辑层没有定义接口族,而是强耦合于表示层中,这可能是因为考虑到在这个系统中业务逻辑没有更改的可能。另外由于是个示例,不是真正的B2C系统,所以业务逻辑层很简单。)

      好了,本系列文章就到这里。希望各位朋友通过这三篇文章,能对“面向接口编程”有一定的了解。当然,我只是起到一个抛砖引玉的作用,其真正的内涵和精髓,还需要各位从实践中慢慢认识。还有,就是面向接口思想不是孤立的,它和设计模式等内容都是面向对象大系中的精华,而且是相互渗透、相互联系的。其实,很多设计模式就是面向接口思想的体现。我们应该把这些放在一起学习,从而真正提供自己的面向对象思考能力和实战能力。

作者:T2噬菌体
出处:http://leoo2sk.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。Tag标签: 面向接口,思想,软件工程,接口,面向对象posted @ 2008-04-14 11:15 EricZhang(T2噬菌体) 阅读(5278) 评论(36)  编辑 收藏 网摘 所属分类: 面向对象技术
发表评论  回复  引用     #1楼 2008-04-14 11:36 | 时刻关注 [未注册用户] 强烈建议博主将自己的专业知识写成系列文章!
出书也行啊,我刚买了伍迷的《大话设计模式》,很不错的,建议你也这么做!!!
  回复  引用  查看     #2楼 2008-04-14 11:42 | HCY       读后很有收获,尤其对于我这些新手,谢谢~
PS:
视图:负责将用户的行为解释给模型。根据指定的策略和用户的操作,调用模型的逻辑。

这里应该是控制器吧
  回复  引用  查看     #3楼 [楼主]2008-04-14 11:46 | T2噬菌体       @HCY
抱歉……笔误了
已经改正,十分感谢您的提醒!!!
  回复  引用  查看     #4楼 [楼主]2008-04-14 11:47 | T2噬菌体       @时刻关注
呵呵,我资质太浅,出书可不敢。不过很原意在Blog里和朋友们讨论软件开发技术:)
  回复  引用  查看     #5楼 2008-04-14 12:03 | 无名小卒       如果没有设计模式的基础,读上文可能会有些困难,希望各位见谅!我打算在以后专门写文章来解析MVC。

期待呀。。。。。。。。。。。。。
  回复  引用  查看     #6楼 2008-04-14 13:01 | 水言木       楼主文中有句:MVC是一种用于表示层设计的复合设计模式。
这么说来MVC就是三层架构中的表示层中更详细的设计咯?对于MVC和三层架构的结合我还是有点不太明白,MVC中的M感觉有点像业务对象,V像三层中的表示层,C则像业务逻辑层,我可以这样理解么?另外,在实际中要如何结合MVC和三层架构呢?
同时期待楼主再写一系列更详细的三层架构文章:)
  回复  引用  查看     #7楼 [楼主]2008-04-14 13:34 | T2噬菌体       @水言木
恩,这个问题我曾经也很困扰。简单来说,MVC中的M和业务逻辑层确实是有交集的,但不等于业务逻辑。而且MVC中的V仅仅是视图,没有表示逻辑(如页面的跳转)。表示层是个更广的定义,除了视图部分,还有表示逻辑。以后我会试着写文章解析这个问题。当然对这个地方我也不是特别精通,希望有高人可以指点一下

  回复  引用  查看     #8楼 2008-04-14 14:47 | 水言木       @T2噬菌体
恩,期待楼主的文章
  回复  引用  查看     #9楼 2008-04-14 16:35 | 崔为福       博主的文笔我很佩服,搞计算机的能有这样的表达能力确实不简单!
  回复  引用  查看     #10楼 2008-04-14 16:40 | 杨子       顶LZ~~~~~~~~
不错哦
  回复  引用  查看     #11楼 2008-04-14 17:14 | andy65007       “在.NET平台上,比较经典的分层架构是三层架构,从下到上依次是:数据访问层、业务逻辑层、表示层”这个和MVC的三层架构有什么区别?是一回事吗?
  回复  引用  查看     #12楼 2008-04-14 17:20 | good man       很好的文章,支持一下
  回复  引用  查看     #13楼 2008-04-14 17:33 | SZW       楼主能写的这么精彩至少说明对这方面知识的理解很扎实很充分。

@水言木
@andy65007
MVC和三层架构(.NET)的结合问题上我觉得不用太转牛角尖,他们虽然看上去都是“三层”,但是一旦真的放到一个系统,你会发现很多问题(原本就不应该是一家的嘛),比如楼主说到的.NET PetShop4用设计思想的就是比较经典的“三层结构”,而这个系统如果用MVC设计的话,其中M层就可以包含PetShop中Model和SQLDAL的几乎所有内容,而剩下的V和C也绝对不是简单地把Web项目中的视图和逻辑拆开就行了,那样的话几乎任何把数据层分离开来的系统都有希望叫"MVC"了(事实上使用WebForms项目你也无法把PetShop简单拆成MVC结构,充其量是MVP——当然MVC和MVP不是包含与被包含的关系),而事实上这么做只是实现了分离,MVC所实现的“分离”一部分建立在这种思想上,但是还要严格很多,同样是分离之后的“三层”,从名字上可以看出他们负责的主要任务是不同的,尤其是MVC的C层。

楼主先说MVC后说三层确实可能会误导到不少人哦:)如果MVC的例子全部换成PetShop的模型来分析可能会更清楚一些。
  回复  引用  查看     #14楼 [楼主]2008-04-14 17:45 | T2噬菌体       @SZW
嗯,呵呵,说的很对。当时没考虑到这可能会混淆MVC和分层架构。以后写一些文章详细解释这两种架构吧……
  回复  引用  查看     #15楼 2008-04-14 19:04 | TT.Net       还是比较喜欢博主第二篇的文章形式,代码与文字并存,全文字的我看到一半就不想看了。
  回复  引用  查看     #16楼 [楼主]2008-04-14 19:18 | T2噬菌体       @TT.Net
嗯,全文字的看起来确实比较累也比较枯燥。以后写文章会注意尽量多用例子说话
  回复  引用  查看     #17楼 2008-04-14 22:28 | BigBar       对于我这个初学者,看到这样的文章是荣幸!
  回复  引用  查看     #18楼 2008-04-15 08:49 | 李战       好!
  回复  引用  查看     #19楼 2008-04-15 12:23 | 生鱼片      
  回复  引用     #20楼 2008-04-15 17:08 | 傻子林 [未注册用户] 不回帖对不起楼主。
好文收藏了。
楼主继续努力,多写文章。哈哈
  回复  引用  查看     #21楼 2008-04-15 17:40 | 小Q       确实很不错.要好好学习下理论知识!
  回复  引用     #22楼 2008-04-16 23:27 | mtn [未注册用户] 写的非常好,理解深刻,深入浅出,期待能继续有更好的文章,尤其是在面向对象和分析设计方面!!
  回复  引用  查看     #23楼 2008-05-06 18:00 | 笑看苍天       不错,顶一个!
  回复  引用  查看     #24楼 2008-05-18 14:27 | Zhuang miao       很好
  回复  引用  查看     #25楼 2008-06-17 15:26 | 小庄       呵呵,我又来发表不同意见了;
关于这篇文章我其实啥也不想说,原因是楼主啥也没写!
  回复  引用  查看     #26楼 2008-06-18 22:52 | coder_dream       讲解的非常好,谢谢!
  回复  引用  查看     #27楼 2008-07-13 16:12 | 王孟军!       楼主讲得好,一句话,面向接口 就是依赖接口,不依赖具体的类
  回复  引用  查看     #28楼 2008-07-19 16:12 | zhuds       不错,顶一个!

  回复  引用  查看     #29楼 2008-07-28 11:19 | 凤&杰¥天下       艾 ,看到这么多知识 很是向学习 只是自己基础太差 希望博主 能够 多发一些简单 易懂的 照顾我们这些初学者啊! 其实我看出 你已经 很在照顾我们了 o(∩_∩)o... 剩下 就考自己了。 希望博主能够再接再厉 闯自己的一片天地了 祝福你呦! 因为 这是你赢得了 , 付出==收获啊! 希望博主有好东西的时候给我介绍一下 谢谢!@
  回复  引用  查看     #30楼 2008-07-30 16:13 | 尚希杰       非常不错,精髓
  回复  引用  查看     #31楼 2008-08-05 00:44 | 唐朝程序员       受教了。。谢谢。。。
  回复  引用     #32楼 2008-10-20 15:55 | 无知.NET2 [未注册用户] 好文章,顶下
  回复  引用  查看     #33楼 2008-11-15 23:51 | 李胜攀       不错,支持一下。
  回复  引用     #34楼 2008-11-24 14:23 | benzhuo [未注册用户] 好文章,学到了很多,谢谢
  回复  引用     #35楼 2008-12-27 12:15 | hxmupdata [未注册用户] 写的很好哦。就顶吧~~~~~~~~~~~~~~~~~
  回复  引用     #36楼 2009-01-07 09:54 | aabbccdda [未注册用户] 对于一下段落,有点不成熟的意见,仅供讨论
"在这个架构中,每一层都不是一个类,而是一个类族,例如,在一个CMS系统中,数据访问层可能会有一系列的类,分别负责用户、文章、评论等业务实体的数据访问操作,而业务逻辑层也一样。如果我们直接依赖,即业务逻辑层实例化数据访问层的类,表示层再实例化业务逻辑层的类,会造成强耦合。如果我想把数据库从 SQLServer换成MySQL,则要改变整个业务逻辑层代码,这是个不好的设计。(还记得“开放-关闭”原则吗)所以,一般的做法是,为数据访问层和业务逻辑层分别定义一族接口,业务逻辑层不依赖具体的数据访问层,而是仅依赖数据访问层的接口族,表示层也一样,依赖业务逻辑层的接口族。如此一来,当要更换数据库时,我们就不必改写整个业务逻辑层,因为业务逻辑层里根本没有任何数据访问层中的具体类,而全是通过接口实现的。在.NET中,只要配合配置文件和反射机制,再运用Abstract Factory设计模式,就可以实现“依赖注入”,即在不改动代码的情况下根据配置选择相应的层次组件。这样,我们就可以为不通数据库分别实现数据访问层,也可以编写ORM的数据访问层,甚至是基于XML的,只要实现了数据访问层接口族,就可以和业务逻辑层无缝连接,从而极大提高了软件的灵活性和可维护性。当然要更改业务逻辑层也是一样。"

>实际开发中, 如果出现了更换数据库等情况, 可以通过使用第三方架构, 如Hibernate等来避免代码修改. 对于依赖注入, 虽然是一种受人推崇的模式, 但在开发中, 会遇到不易调试等问题, 反而直接实例化更容易理解.