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

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

这篇的内容可能会比较抽象,望谅解。

1.从MVC开始

MVC简介:

本文不打算详细解释MVC架构,而是把重点放在其中的面向接口思想上。所以在这里,只对MVC做一个简略的介绍。

MVC是一种用于表示层设计的复合设计模式。M、V、C分别表示模型(Model)、View(视图)、Controller(控制器)。它们的职责如下:

模型:用于存储应用中的数据及运行逻辑,是应用的实体。

视图:负责可视部分,用于与用户交互及呈现数据。视图只负责显示,不负责将用户的操作行为解释给模型。

控制器:负责将用户的行为解释给模型。根据指定的策略和用户的操作,调用模型的逻辑。

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

图3.1 MVC模式示意

它们之间的交互有以下几种:

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系统,所以业务逻辑层很简单。)

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

转载于:https://www.cnblogs.com/gzskys/p/5598703.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/372779.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

错误学习:Java + OSGi

最近,我致力于在OSGi环境中使Apache Hive工作。 虽然没有被证明是小菜一碟(软件对吗?。。为什么我不感到惊讶? ),它引导我解决了各种Java和OSGi错误。 在这里,我列出了其中一些让我有些吃力的东…

iOS多Targets管理

序言: 个人不善于写东西,就直奔主题了。 其实今天会注意到多targets这个东西,是因为在学习一个第三方库FBMemoryProfiler的时候,用到了,所以就搜索了一些相关资料,就在这里记录一下。 可能每个人都会遇到这…

优化的34条定律

1.Minimize HTTP Requests 减少HTTP请求 图片、css、script、flash等等这些都会增加http请求数,减少这些元素的数量就能减少响应时间。把多个JS、CSS在可能的情况下写进一个文件,页面里直接写入图片也是不好的做法,应该写进CSS里,…

休眠提示:排序和排序

让我们介绍另一个休眠性能提示。 你还记得以前的休眠的模式后 ? 我们有一个与一对多协会有关的星际飞船和军官。 Entity public class Starship {Id GeneratedValue(strategyGenerationType.SEQUENCE) private Long id;public Long getId() {return id;}protected v…

java 基本类型 线程安全_java的基本类型和i++线程安全性的深入解析

在java中,除了long和double的8个字节、64位比特的变量外,其他的基本变量都是原子性的。java存储模型要求获取和存储操作都为原子性,但是对于非volatile的long和double变量,jvm允许将64位的读或写划分为两个32位的操作。如果读和写…

MySQL配置文件mysql.ini参数详解

my.ini(Linux系统下是my.cnf),当mysql服务器启动时它会读取这个文件,设置相关的运行环境参数。 my.ini分为两块:Client Section和Server Section。 Client Section用来配置MySQL客户端参数。 要查看配置参数可以用下面…

微信公众平台和微信开放平台的区别

自己也刚开始做微信开发,先写写自己的认识: 用微信公众平台可以做手机端H5页面的微信登录,微信支付 用微信开放平台可以做PC端网页的微信登录。 转载于:https://www.cnblogs.com/mafeng/p/5610770.html

java 传递bean_如何将bean作为参数传递给JSP标记?

我ve created a custom JSP tag that is supposed to accept a list of products to render, but I我无法弄清楚如何将列表传递给标签 . 产品列表作为页面范围的bean存在 . Web应用程序使用Struts taglib在Struts 1.2.x中编写 .这是我的代码的简化版本:renderProduc…

Business Component(BC)和Business Object(BO)

Siebel应用架构的一个成功的地方就是在应用里引入了BC,BO的概念,从而使得几千张关系数据表能够按照业务的含义组织成业务对象,对于业务人员而言具有了业务上的含义,而不仅仅是从技术人员的观点来对待数据(就是关系表而…

NetBeans可用性提示

的Java IDE都来了,因为在很长的路要走天的JBuilder的 (尽管JBuilder中似乎是一个值得欢迎提前在时间)。 当今的Java IDE(例如NetBeans , Eclipse , IntelliJ IDEA和JDeveloper )是非常先进的工具…

一个JVM进程启动后里面有几个线程

在写Java程序时,通常我们管只有一个main函数(而没有别的Thread或Runnable的程序)叫单线程程序。但是我们写的这个所谓的单线程程序只是JVM这个程序中的一个线程,JVM本身是一个多线程的程序,至少得有一个垃圾收集器线程…

WPF 反编译后错误处理

1. 首先,手动创建一个WPF工程(WpfApplicationReflectorDemo) 2. 把生成的WpfApplicationReflectorDemo.exe 拖到ILSpy里 3.点击 File -> Save Code...: 相应的代码会生成到指定地方。 4. 打开应用程序,并且编译它,此…

JavaFX 2 GameTutorial第1部分

介绍 我相信大多数软件开发人员可能会在年轻人(年轻人)一生中的某一时刻被迫创建游戏来帮助他们学习编程语言(我知道我确实做到了)。 以前,我的第一台计算机实际上是Franklin Ace 1000 ,后来是Apple [] 。 …

虚拟现实-VR-UE4-认识UE4

VR的火热,让每个人都想参与一下, 公司在展会上面搞了一个VR的Demo,关注度超出预期,使得公司高层决定来个VR项目 所以 关于UE4 百度百科地址:http://baike.baidu.com/link?urlmEmbwOcqEuqtkfdu9lNdxVtWAkv0Q6UHZ4VgIHr…

java concurrent 例子_[Java Concurrent] 并发访问共享资源的简单案例

EvenGenerator 是一个偶数生成器,每调用一个 next() 就会加 2 并返回叠加后结果。在本案例中,充当被共享的资源。EvenChecker 实现了 Runnable 接口,可以启动新的线程执行 run() 任务,用于检测所指向的偶数生成器是否每次都返回偶…

OSGI实战第一章

第一章 解开OSGI的面纱 OSGI是什么?是Java平台的一个模块化层。模块化:软件应用程序的代码被分割为表示独立内容的逻辑单元,可简化开发,可通过强化逻辑模块的界限来提高可维护性。Java模块化的不足a) Java使用访问…

轻松完成Birt报告

这是使用Birt插件在Eclipse中构建报告的完整指南。 Birt或Business Intelligence and Reporting工具是一种无需编写太多Java代码即可生成报告的工具。 如果您使用的是ireport,那么您知道我在说什么:)(晶体报告..毫无意义&#xff…

MySQL 的 RowNum 实现

MySQL 下面没有RowNum,排序后序号却无法得到,比较麻烦! SELECT rownum:rownum1 rownum, CollectSn From(SELECT rownum:0,bbgmain.* FROM qbdb.bbgmain WHERE collectsn! ORDER BY collectsn limit 10) t转载于:https://www.cnblogs.com/hym-…

java jdbc事务管理_hibernate事务管理 (jdbc jta)

评论# re: hibernate事务管理 (jdbc jta)2007-07-29 10:18pigJTA事务的开始Transaction tx session.beginTransaction();应该不是这样吧,应该是从容器中获得。 回复 更多评论# re: hibernate事务管理 (jdbc jta)2007-07-29 12:35slxpig建议看看hibernate referen…

@Resource VS @Autowired

Resource 和 Autowired 均是用于bean注入的注解,都可以写在字段和setter方法上,如果都写在字段上,就无需写setter方法。 Autowired 由Spring的org.springframework.beans.factory.annotation.Autowired提供 默认byType方式注入,并且对象不能为…