目录

用组合模式、策略模式、观察者模式结合来实现一个MVC

1 MVC介绍

众所周知MVC不是设计模式,是一个比设计模式更大一点的模式,称作设计模式不合理,应该说MVC它是一种软件开发架构模式,它包含了很多的设计模式,最为密切是以下三种:Observer (观察者模式), Composite(组合模式)和Strategy(策略模式)。所以说MVC模式又称复合模式。MVC(Model-View-Controller) 模式的基本思想是数据,显示和处理相分离。模型(Model)负责数据管理,视图(View)负责数据显示,控制器(Controller)负责业务逻辑和响应策略。

从MVC的形成过程来看,最初只有模型和视图两个元素。模型封装了数据并提供操作接口,视图用来表现数据和接收用户请求。模型是独立的,而视图依赖于模型:从模型获取数据进行显示;向模型发送用户请求,并根据返回结果刷新自己。

需要用多个视图表现同一模型时,情况发生了变化:一个视图修改数据以后,不但本身要刷新,其他所有视图也要刷新。如果由该视图通知其他视图,它就需要知道其他所有视图,由于每个视图都可能发出修改,每个视图都要知道其他所有视图,这种关联过于复杂,不但难以维护,而且不便于增加新的视图。如果让模型通知所有视图更新,可能会影响模型的独立性。用观察者(Observer)模式 可以解决上述矛盾,从而实现:由模型通知视图,而模型不依赖于具体的视图,具体视图之间相互独立。

视图是用户请求的接收者,但不宜作为请求的处理者。因为界面是易变的,如果业务代码和界面代码放在一起,频繁的界面修改可能会破坏比较稳定的业务代码。将业务逻辑分离出来,由一个控制器负责,就是为了避免这种干扰。

模型,视图和控制器的基本协作关系如下图

./1.gif

模型在状态变化的时候,直接通知所有视图,视图向模型查询状态数据,然后刷新自身。当用户发出操作时,视图把消息发给控制器,控制器按照业务逻辑进行处理,需要查询或更新数据时,控制器会调用模型。下面是一个更详细的示意图

./2.gif

MVC架构把数据处理,程序输入输出控制及数据显示分离开来,并且描述了不同部件的对象间的通信方式。使得软件可维护性,可扩展性,灵活性以及封装性大大提高;MVC(Model-View-Controller)把系统的组成分解为M(模型)、 V(视图)、C(控制器)三种部件。视图表示数据在屏幕上的显示。控制器提供处理过程控制,它在模型和视图之间起连接作用。控制器本身不输出任何信息和做任何处理,它只负责把用户的请求转成针对Model的操作,和调用相应的视图来显示Model处理后的数据。三者之间关系如下图2.1:

./3.jpg

图2.1 MVC关系图

同样的数据,可以有不同的显示和进行各种处理。显示仅仅是表现数据,而处理是根据用户请求改变数据的过程,不但包含业务逻辑,也要提供响应策略。响应策略由控制器负责,视图可以使用不同的控制器提供不同的响应方式,这是策略(Strategy)模式的应用。

此外,MVC还允许视图嵌套,通过使用组合(Composite)模式,一致地处理组合视图和普通视图。

用多个视图表现一个模型,在视图不变的情况下改变响应策略,允许视图嵌套,这是MVC的三个主要特性。在内部结构上,MVC的主要关系是由观察者模式,策略模式和组合模式给出的。由观察者模式确定的模型视图关系是其中最为重要的。

MVC 模式有许多变体。前述结构中,由模型通知视图刷新,称为主动MVC;如果由控制器更新模型以后通知视图,称为被动MVC结构。在许多应用中,没有明显的控制器角色,也没有视图嵌套。可见根据实际需要,构成MVC的三个模式上都可能出现变化。Web浏览器就是被动MVC结构的一个实例。

./4.gif

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

2.为什么要在Web应用中使用MVC架构

用户界面逻辑的更改往往比业务逻辑频繁,尤其是在基于Web的应用程序中。例如,可能添加新的用户界面页,或者可能完全打乱现有的页面布局。对显示的更改,尽可能地不要影响到数据和业务逻辑。

目前大部分Web应用都是将数据代码和表示混在一起。经验比较丰富的开发者会将数据从表示层分离开来,但这通常不是很容易做到的,它需要精心的计划和不断的尝试。MVC从根本上强制性的将它们分开。尽管构造MVC应用需要一些额外的工作,但它带来的好处是无庸质疑的。

2.1 提高代码重用率

最重要的一点是多个视图能共享一个模型,无论用户想要Flash界面或是 WAP 界面;用一个模型就能处理它们。由于已经将数据和业务规则从表示层分开,所以可以最大化的重用代码。

2.2 提高程序的可维护性

因为模型是自包含的,并且与控制器和视图相分离,所以很容易改变数据层和业务规则 [3]。例如,把数据库从MySQL移植到Oracle,或者把基于RDBMS数据源改变到LDAP,只需改变模型即可。一旦正确的实现了模型,不管数据来自哪里,视图都会正确的显示它们。MVC架构的运用,使得程序的三个部件相互对立,大大提高了程序的可维护性。

2.3 有利于团队开发

在开发过程中,可以更好的分工,更好的协作。有利于开发出高质量的软件。良好的项 目架构设计,将减少编码工作量 :采用MVC结构 + 代码生成器,是大多数Web应用的理想选择。部分模型(Model)、和存储过程一般可用工具自动生成。控制(Controller)器比较稳定,一般由于架构师(也可能是有经验的人)完成;那么整个项目需要手动编写代码的地方就只有视图(View)了。在这种模式下,个人能力不在特别重要,只要懂点语法基础的人都可以编写,无论项目成员写出什么样的代码,都在项目管理者的可控范围内。即使项目中途换人,也不会有太大问题。在个人能力参差不齐的团队开发中,采用MVC开发是非常理想的。

3 MVC架构的优点及不足

3.1 MVC的优点

MVC的优点体现在以下几个方面:

(1) 有利于团队开发分工协作和质量控制,降低开发成本。

(2) 可以为一个模型在运行时同时建立和使用多个视图。变化-传播机制可以确保所有相关的视图及时得到模型数据变化,从而使所有关联的视图和控制器做到行为同步。

(3) 视图与控制器的可接插性,允许更换视图和控制器对象,而且可以根据需求动态的打开或关闭、甚至在运行期间进行对象替换。

(4) 模型的可移植性。因为模型是独立于视图的,所以可以把一个模型独立地移植到新的平台工作。需要做的只是在新平台上对视图和控制器进行新的修改。

(5) 潜在的框架结构。可以基于此模型建立应用程序框架,不仅仅是用在设计界面的设计中。

3.2 MVC的缺点

MVC的不足体现在以下几个方面:

(1)增加了系统结构和实现的复杂性。对于简单的界面,严格遵循MVC,使模型、视图与控制器分离,会增加结构的复杂性,并可能产生过多的更新操作,降低运行效率。

(2)视图对模型数据的访问效率低。视图可能需要多次调用Model才能获得足够的显示数据。

(3)完全理解MVC并不是很容易。使用MVC需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。同时由于模型和视图要严格的分离,这样也给调试应用程序到来了一定的困难。

MVC 模式可以分解为以下设计模式

在GOF书的 Introduction中,有一小节是"Design Patterns in Smalltalk MVC"即介绍在MVC模式里用到的设计模式。它大概向我们传达了这样的信息:合成模式+策略模式+观察者模式约等于MVC模式(当然MVC模式要多一些东西)。也就是说它在大部分情况下是下面几个模式:

1、观察者模式

类图结构在Gof里的表示如下:

2、合成模式 类图结构在Gof里的表示如下:

./5.png

3、策略模式

类图结构在Gof里的表示如下:

./6.gif

谈 谈 MVC 架构模式中的三个角色

  • Model (模型端)

Mod封装的是数据源和所有基于对这些数据的操作。在一个组件中,Model往往表示组件的状态和操作这些状态的方法,往往是一系列的公开方法。通过这些公开方法,便可以取得模型端的所有功能。

在这些公开方法中,有些是取值方法,让系统其他部分可以得到模型端的内部状态参数,其他的改值方法则允许外部修改模型端的内部状态。模型端还必须有方法登记视图,以便在模型端的内部状态发生变化时,可以通知视图端。我们可以自己定义一个Subject接口来提供登记和通知视图所需的接口或者继承 Java.util.Observable类,让父类完成这件事。

  • 多个 View( 视图端 )

View封装的是对数据源Model的一种显示。一个模型可以由多个视图,并且可以在需要的时候动态地登记上所需的视图。而一个视图理论上也可以同不同的模型关联起来。

在前言里提到了,MVC模式用到了合成模式,这是因为在视图端里,视图可以嵌套,比如说在一个JFrame组件里面,可以有菜单组件,很多按钮组件等。

  • 多个 Controller( 控制器端 )

封装的是外界作用于模型的操作。通常,这些操作会转发到模型上,并调用模型中相应的一个或者多个方法(这个方法就是前面在介绍模型的时候说的改值方法)。一般Controller在Model和View之间起到了沟通的作用,处理用户在View上的输入,并转发给Model来更改其状态值。这样 Model和View两者之间可以做到松散耦合,甚至可以彼此不知道对方,而由Controller连接起这两个部分。也在前言里提到,MVC用到了策略模式,这是因为View用一个特定的Controller的实例来实现一个特定的响应策略,更换不同的Controller,可以改变View对用户输入的响应。

MVC (Model-View-Controller) : 模型利用"观察者"让控制器和视图可以随最新的状态改变而更新。另一方面,视图和控制器则实现了"策略模式"。控制器是视图的行为; 视图内部使用"组合模"式来管理显示组件。

以下的MVC解释图很好的标示了这种模式:

http://192.168.1.246:88/wiki/download/attachments/7831556/02-mvc_in_fleaphp.png?version=1&modificationDate=1232159466000

C:\Program_Green\hugo_extended_0.82.0_Windows-64bit\sites\KKKPJSKEY's-Case-Archives\content\posts\MVC-Design-Patterns\9.jpg

  • 模型使用观察者模式,以便观察者更新,同时保持两者之间的解耦。
  • 控制器是视图的策略,视图可以使用不同的控制器实现,得到不同的行为。
  • 视图使用组合模式实现用户界面,用户界面通常组合了嵌套的组件,像面板、框架和按钮。
  • 这些模式携手合作,把MVC模式的三层解耦,这样可以保持设计干净又有弹性。