MVC模式和文档/视图结构

        MVC(Model-View-Controller)模式的基本思想是数据,显示和处理相分离。模型(Model)负责数据管理,视图(View)负责数据显示,控制器(Controller)负责业务逻辑和响应策略。
       从MVC的形成过程来看,最初只有模型和视图两个元素。模型封装了数据并提供操作接口,视图用来表现数据和接收用户请求。模型是独立的,而视图依赖于模型:从模型获取数据进行显示;向模型发送用户请求,并根据返回结果刷新自己。
       需要用多个视图表现同一模型时,情况发生了变化:一个视图修改数据以后,不但本身要刷新,其他所有视图也要刷新。如果由该视图通知其他视图,它就需要知道其他所有视图,由于每个视图都可能发出修改,每个视图都要知道其他所有视图,这种关联过于复杂,不但难以维护,而且不便于增加新的视图。如果让模型通知所有视图更新,可能会影响模型的独立性。用观察者(Observer)模式可以解决上述矛盾,从而实现:由模型通知视图,而模型不依赖于具体的视图,具体视图之间相互独立。
       视图是用户请求的接收者,但不宜作为请求的处理者。因为界面是易变的,如果业务代码和界面代码放在一起,频繁的界面修改可能会破坏比较稳定的业务代码。将业务逻辑分离出来,由一个控制器负责,就是为了避免这种干扰。
       模型,视图和控制器的基本协作关系如下图
clip_image001
       模型在状态变化的时候,直接通知所有视图,视图向模型查询状态数据,然后刷新自身。当用户发出操作时,视图把消息发给控制器,控制器按照业务逻辑进行处理,需要查询或更新数据时,控制器会调用模型。下面是一个更详细的示意图
clip_image002
clip_image003
       同样的数据,可以有不同的显示和进行各种处理。显示仅仅是表现数据,而处理是根据用户请求改变数据的过程,不但包含业务逻辑,也要提供响应策略。响应策略由控制器负责,视图可以使用不同的控制器提供不同的响应方式,这是策略(Strategy)模式的应用。
       此外,MVC还允许视图嵌套,通过使用组合(Composite)模式,一致地处理组合视图和普通视图。
       用多个视图表现一个模型,在视图不变的情况下改变响应策略,允许视图嵌套,这是MVC的三个主要特性。在内部结构上,MVC的主要关系是由观察者模式,策略模式和组合模式给出的。由观察者模式确定的模型视图关系是其中最为重要的。
       MVC模式有许多变体。前述结构中,由模型通知视图刷新,称为主动MVC;如果由控制器更新模型以后通知视图,称为被动MVC结构。在许多应用中,没有明显的控制器角色,也没有视图嵌套。可见根据实际需要,构成MVC的三个模式上都可能出现变化。Web浏览器就是被动MVC结构的一个实例。

clip_image004
       “浏览器是一个交互程序,从概念上讲,它是由一组客户、一组解释器与一个管理它们的控制器所组成。控制器形成了浏览器的中心部件,它解释鼠标点击与键盘输入,并且调用其他组件来执行用户指定的操作。例如,当用户键入一个URL或者点击一个超文本引用时,控制器调用一个客户从所需文档所在的远程服务器上取回该文档,并且调用解释器向用户显示该文档。每个浏览器必须包含一个HTML解释器来显示文档,其他解释器是可选的。HTML解释器的输入由符合HTML语法的文档所组成,输出由位于用户显示器上的格式版本文档所组成。解释器通过将HTML规则转换成适合用户显示硬件的命令来处理版面细节。HTML解释器一个最重要的功能是包含可选项。解释器必须存储关于显示器上位置之间关系的信息和HTML文档中被瞄定的项。当用户用鼠标选定了一个项,浏览器通过当前的光标位置和存储的位置信息来决定哪个项被用户选定。”(参考资料5)

       MFC的文档/视图结构(Document/View architecture)是MVC模式的一种变体,下面讨论它是怎样实现的。
       文档/视图结构没有体现业务逻辑和视图的分离,但是将响应策略和视图区分开来。它主要包含四种对象:

1. 文档

2. 视图

3. 视图框架窗口

4. 文档模板

       这里的视图框架窗口定义了视图对用户输入的响应方式,而文档模板用来管理前三种对象的组合。文档,视图,视图框架窗口三者是对应的,从而构成一个三元组。一个应用程序可能需要多个这样的三元组,以实现文档的多视图,所以引入文档模板来表示该三元组。因为程序中可能使用多个文档模板,MFC用一个文档管理者对象来管理它们。
       在MFC中,应用程序和主框架窗口是用来封装底层机制的对象,文档,视图,视图框架窗口和文档模板是用来构架文档/视图结构的对象。应用程序通过文档管理者来使用文档/视图结构。
       如果要给文档增加一种视图,只需要增加一个文档模板;如果要改变一种视图的响应策略,只要改变对应文档模板中的视图框架窗口。

 

==================================================================================================================

       软件设计中会碰到这样的关系:一个对象依赖于另一个对象,必须根据后者的状态更新自己的状态,可以把后者称作目标对象,前者称作观察者对象。不但观察者依赖于目标,当目标的状态改变时也要通知观察者,这就出现了双向的依赖。两个对象互相依赖的后果是它们必须一起复用。如果一个目标有多个观察者,那么目标也依赖所有观察者,从而目标对象无法独立复用。如何消除目标和观察者之间的互相依赖呢?观察者模式帮助我们解决这个问题。
观察者模式把目标对观察者的依赖进行抽象:使目标只知道自己有若干观察者,但不知道这些观察者具体是谁,可能有多少个;当目标状态改变时只要给这些观察者一个通知,不必作更多的事情。这样目标对观察者的依赖就达到了抽象和最小,而目标对具体观察者的依赖被解除了。
       类图如下:
clip_image001[5]clip_image002
       Subject对象保存一个Observer引用的列表,当我们让一个ConcreteObserver对象观察Subject对象时,调用后者的Attach()方法,将前者的引用加入该列表中。当Subject对象状态改变时,它调用自身的Notify方法,该方法调用列表中每一个Observer的Update()方法。一个ConcreteObserver只要重定义Update()就能收到通知,作为对通知的响应,Update()调用Subject对象的getStatus()获取数据,然后更新自身。当不需要继续观察时,ConcreteObserver对象调用Subject对象的Detach()方法,其引用被从列表中移除。


       解除目标对具体观察者的依赖以后,很容易增加新的具体观察者,因为不受依赖的方面就可以自由变化;而目标也可以独立地复用,因为无所依赖的方面就可以不受影响。
       以上主要考虑了一个目标有多个观察者的情况,我们设法解除了目标对具体观察者的依赖,使具体观察者的种类和数目容易改变。有时候一个观察者观察多个目标也是有意义的,在前面的类图中,观察者对具体目标的依赖仍然存在,因此无法适应目标方面的变化。怎样抽象这种依赖呢?使观察者只知道若干个目标会向自己发出通知,而不知道这些目标具体是谁,可能有多少个;在目标向观察者发送通知时,将一个自身的引用作为参数,然后观察者调用其抽象方法就可以获得目标状态。这就使得观察者对目标的依赖是抽象的,观察者对具体目标的依赖被解除了。
       类图如下:
clip_image003

 


参考资料:
1.《设计模式-可复用面向对象软件的基础》/Erich Gamma等著,李英军等译 机械工业出版社
2.《Java与模式》/阎宏 电子工业出版社
3.  模型-视图-控制器 ( MSDN > 技术资源库 > 体系结构 > 使用 Microsoft .NET 的企业解决方案模式 >第3章 Web 表示模式)
4. 《Java设计:对象,UML和过程》/Kirk Knoernschild 著,罗英伟等译 人民邮电出版社
5. 《计算机网络与因特网》/D.E.Comer 著 徐良贤等译 机械工业出版社
6.《深入解析MFC》/中国电力出版社
7.《VC技术内幕》第5版 / 希望电子出版社

转载地址:

http://www.cppblog.com/woaidongmao/archive/2010/11/16/58017.html

posted @ 2022-03-12 22:04  xiaomodecnblogs  阅读(80)  评论(0编辑  收藏  举报