MVC(模型—视图—控制器)模式
MVC将用户接口问题分割为三个截然不同的部分:模型、视图和控制器。模型存储应用的状态。视图解释模型中的数据并将它展示给用户。最后控制器处理用户的输入。
因为表示层是请求驱动的,所以“用户”可以是任意请求的发起者。控制器处理该请求。模型就是业务数据,而视图就是最终发生的应答。控制器是与请求发生联系的起点。控制器就是一个主管,首先规划要做哪些更新和要显示什么视图,然后调用被选择的模式和视图以执行真正的规划。模型的工作是管理对该状态的访问,为控制器和视图提供统一的接口。视图从模型中读取数据,并使用这些数据来生成应答。
从某种程度上来说,J2EE内置了MVC的概念。表达层通常由三个主要的组件构成:Servlet、JSP和JavaBean。JavaBean和EJB形式的模型提供对业务层数据的访问。控制器通常就是一些Servlet和支撑类的集合,用于处理输入和控制导航。最终,视图一般实现为JSP页面和静态HTML。遗憾的是,在J2EE背景中,视图和控制器的分界线很容易混淆。使用Servlet的RequestDispatcher对象来转移控制权,该对象可以用于在服务器内转发请求。通过使用RequestDispatcher,我们可以把请求发送给多个servlet、JSP页面或者不涉及客户端的静态HTML页面。视图是没有状态的。每次它被调用的时候,它必须读取模型数据并把它转换为HTML页面格式。视图必须能够从模型中读取出它的数据。因为控制器已经把JavaBean形式的模型存储在请求中了。虽然使用JavaBean作为模型、JSP作为视图、Servlet作为控制器的思想并不是必须的,但是这是一种很好的经验法则。更重要的是要理解模型、视图和控制器之间的分离怎么使应用可扩展和可维护。
FrontController(前端控制器)模式
控制器不仅是接触请求的起点,它还是我们编程量最多和设计自由度最大的地方。前端控制器(Front Controller)模式主张构建一个单独的控制器执行每个请求中都需要的公共功能,而将其他的功能委托给与页面相关的控制器。前端控制器(Front Controller)提供了一个统一的位置来封装公共请求处理。前端控制器模式中的主要参与者是控制器本身。它的工作相当简单:执行公共的任务,然后把控制转移给与页面相关的控制器。
页面控制器执行模型更新和视图选择,实际上有些类似MVC模式中的控制器角色。页面控制器可以是完全独立的servlet,但是它们通常都按照GOF提出的命令(Command)模式实现为许多个更简单的类。在这种设计中,许多不同种类的页面控制器共享一个简单的公共接口,而且通常被称作“动作”(源于Command模式)。因为前端控制器选择了页面控制器,所以页面控制器最终负责选择正确的动作和视图。在一个Web应用中,前端控制器几乎总是用一个Servlet来实现。虽然使用JSP页面在技术上也是可行的,但这通常是一个坏主意——JSP页面不应该用于实现复杂的逻辑。第二种更引人注目的选择是使用一个servlet过滤器作为前端控制器。
Decorator(装饰器)模式
装饰器(Decorator)模式把多个小的组件组合成一个大的组件。装饰器是由GOF提出的术语,以说明它本质上是一个包装器:一个包含单个子项目并提供与该子项完全相同接口的类。装饰器为它的子项“装饰”或者添加一项功能。当装饰器上有一个方法被调用的时候,它先做自身的预处理,然后调用子项上的相应方法。产生的结果是一个扩展的响应,就如同原始组件把装饰器的代码嵌入在自己内部一样。装饰器只含有一个子项,但是它们可以形成一条链。装饰器的一条链由多个装饰器组成,每个装饰器都将原始对象装饰在链的末端。每个装饰器的职责就是调用链中下一个对象的方法。装饰器的主要限制在于它只装饰一个组件。这点细节很重要,因为它保证了装饰器可以放置到任意长度的链中。虽然动态添加和删除装饰器很方便,但是过多地这么做会显著地增加复杂性。装饰器应该设计成彼此独立,同时也独立与目标对象,依赖性和顺序关系假设可能会在漏掉某个装饰器或者装饰器添加的顺序错误的时候产生很严重的缺陷。
装饰器的一种关键应用:动态扩展前端控制器。通过链接前端控制器上装饰器的不同组合,我们可以快速地增减控制器上的特性。并且,通过使用装饰器,我们可以有效地降低所有这些不同功能之间的耦合读。
装饰器代表着一种相当简单的扩展对象功能的方式,而面向方面的编程(Aspect-oriented Programming, AOP)则是一种以动态扩展对象为核心的编程方法学。AOP中的一个方面(Aspect)代表一个贯穿多个类的公共概念,例如日志系统。一个方面把用于执行某个动作的代码、它将应用到的目标以及何时应用它的特定条件等所有的东西都封装在一起。某个方面中的条件一旦满足,就执行它里面的代码。在简单的情况下,一个方面的工作看起来与装饰器有些相似。但是各方面提供了许多描述条件的复杂方式,这使它们比装饰器更加强大,同时也更复杂。
Serviceto Worker(服务工作者)模式
服务工作者(Service toWorker)模式建立在模型—视图—控制器模式和前端控制器模式的基础上。服务工作者(Service to Worker)模式的目标是维持动作、视图和控制器之间的分离。服务是指前端控制器这个处理请求的中心。在服务工作者模式中,一个称为调度器的对象执行管理工作者和视图任务。该调度器封装了页面的选择以及随后的工作者选择。它去除了应用的行为与前端控制器间的耦合。
服务工作者模式的最终结果是一个可扩展的前端控制器。
使用服务工作者模式,控制器已经被划分为一组可重用的组件:一个前端控制器,一些调度器和动作。添加新页面是动态的:简单的生产JSP视图和对应的动作类,然后将它们全部添加到一个配置文件中(例如XML文件)。需要添加、删除或者重现排序页面的时候,只需要修改配置文件即可。
ViewHelper(视图助手)模式
一个助手视图相当于模型和视图之间的中介。它读取特定的业务数据并进行转换,有时候直接转换成HTML,有时候则转换成一种中间数据模型。不是由视图来包含用于处理特定模型的特殊代码,而是由这种新视图来包含更通用的对助手的调用。视图助手在两个方面提高了可重用性:降低了一个视图中特殊代码的数量,助手使得视图可以更好的重用;此外,因为助手封装了与模型的特殊交互,所以助手本身也可以被重用。
当考虑使用JSP中的视图助手时,自定义标签马上就会跃入脑海。自定义标签正好适合——它把Java对象改编成JSP标注。将嵌入的代码转变为自定义的标签类降低了耦合性,因为标签定义了一个独立于底层对象的清晰接口。虽然很容易把所有的自定义标签看出视图助手,但是它们并不是相同的东西。一个助手视图是将数据翻译成一种很方便的视图格式的一个标签后者一组标签。
CompositeView(复合视图)模式
复合视图模式是基于GoF的复合模式。其思想非常简单:把对象看成是一种树结构,其中的父节点暴露与其子节点相同的接口。当把这种概念应用到视图中的时候,它意外着将每个页面考虑为大量元素的组合。每个元素可以是一个叶节点,它在屏幕上显示一个实际部件。一个元素还可以是一个容器,它包含多个子元素。容器的子元素可以是叶子节点,也可以是其他容器,结果就产生了类似与数的结构。
复合视图模式是大多数图形化系统的一个支柱。视图代表的是叶子和容器都要实现的一个公共接口。复合中子部件的顺序在某些系统中并不重要,但是在显示时顺序往往时很重要的。
当开发一个Web应用中的时候,使用复合视图提高了用户界面的一致性和视图的可重用性。就像装饰器一样,当它们嵌套很深或者具有太多依赖关系的时候,复合视图可能会带来麻烦。