二、J2EE设计模式
一个设计模式描述了对于特定设计问题被验证的解决方案,它综合了所有开发者对这个问题所在领域的知识和见解;同时也是对于常见问题的可重用方案,它们一般适用于单个问题,但是组织在一起就可以提供整个企业系统的解决方案。下面我们列举八种常用于J2EE平台的设计模式,并对每种模式作简单的介绍,便于大家学习、理解与灵活应用。 1、前控制器 前控制器(front controller)主要提供一种可以集中式管理请求的控制器,一个前控制器可以接受所有的客户请求,将每个请求递交给相应的请求句柄,并适当地响应用户。 前控制器也是表示层的设计模式,它的出现主要是由于表示层通常需要控制和协调来自不同用户的多个请求,而这种控制机制又根据不同的需要,可能会集中式控制或分散式控制。换句话说,就是应用系统需要对于表示层的请求提供一个集中式控制模块,以提供各种系统服务,包括内容提取、视图管理和浏览,如果系统中没有这种集中式控制模块或控制机制,每个不同的系统服务都需要进行单独的视图处理,这样代码的重复性就会提高,致使系统开发代价提高;同时,如果没有一个固定模块管理视图之间的浏览机制,致使其浏览功能下放于每个不同的视图中,最终必将使得系统的可维护性受到破坏;本文中我们主要讨论的是集中式控制模块,而不是分散式控制,因为前者更适合于大型的应用系统。 基于上面所说的问题,研究人员提出了前控制器的设计模式。在这种模式中,控制器提供一个处理不同请求的控制点,这里的处理工作包括安全事务、视图选择、错误处理和响应内容的生成;通过将这些处理工作集中在一点进行,大大地减低了Java代码量,同时这种方法也可以减少在视图模块的程序逻辑,保证了在不同请求之间可以重用大量的逻辑代码。通常,控制器都是和一个分派组件联合工作的,分派组件主要是用于视图管理和浏览,也就是为用户选择下一个应该显示的视图,并同时提供对于相关显示资源的控制。分派组件可以包含在控制器之内,或是在另外一个单独的组件中;虽然前控制器模式推荐对于全部的请求使用统一处理,但是它也没有限制在一个系统中只能具有一个控制器,在系统中的每个层次都可以具有多个控制器,并且映射至不同的系统服务,下图2显示了前控制器的类图。
 图2 前控制器的类图
图3显示了前控制器的序列图,表示一个控制器如何处理相关的请求。
 图3前控制器序列图
下面我们来讨论一下图3的各个组件。 2、控制器 控制器(controller)是负责处理各种客户请求的控制点,并可以将一定的职能(如用户认证等)下放给帮助类。 (1)分派组件(Dispatcher)。一个分派组件主要是用于视图的管理和浏览,为用户选择下一个可以显示的视图,并管理相关的显示资源;分派组件可以在一个控制器内运行,或者作为一个单独的组件与控制器协同工作;开发人员可以在分派组件中实现静态的视图分派技术,或是复杂的动态分派。 (2)帮助类(Helper)。帮助类负责帮助一个视图或控制器来完成其处理工作,因此,帮助类具有多项职责,包括收集数据、存储中间数据模型等;另外,帮助类也可以在保证数据完整性和准确性的情况下,为不同显示需求修改数据模型;也就是说,根据用户的请求,帮助类可以向视图提供未经处理的原始数据,或是已经格式化后的Web内容,一个视图同时可以和多个帮助类协同工作,而后者通常是由JavaBeans和标签(tag)实现的。 3、视图 视图(view)负责向用户显示信息,而帮助类则负责支持视图的工作,即打包和建立相应的数据模型,下面我们介绍几种可以实现控制器的方法。 1)基于Servlet前控制器 这种方法建议使用servlet来实现一个控制器,尽管在语法上相差无几,但是它比使用JSP来实现要优越一些;因为控制器所进行的请求处理,多数都是与程序运行和控制流动相关的,这些处理工作虽然与显示模式相关,但是实际上是逻辑独立的,所以它们更适合在servlet中实现,而不是JSP技术中;使用这种方法也存在一些弱点,比如说servlet无法使用JSP运行环境的资源,如请求参数等,但是这个弱点也不是不能解决的,我们可以在servlet中建立相关的句柄来访问同样的资源,当然其代码会变得繁琐一点。 2)基于JSP的前控制器 这种方法建议使用JSP页面实现控制器,尽管语法上相同,但是Servlet方案要比其优越一些;因为控制器所处理的逻辑一般都不是有关显示模式的,所以在JSP页面中实现控制器似乎有点风马牛不相及;使用这种方法也不利于开发团队的角色和职责的分配,即软件开发人员需要在负责显示逻辑的JSP页面中修改请求处理的代码,通常,这种工作都是相当复杂的,尤其考虑整个JSP页面的编程、编译、测试和调试错误。 3)控制器之中的分派组件 如果分派组件没有较多功能,开发人员可以在控制器实现该组件。 4)基础前端 基于使用servlet实现前控制器,这种方案建议实现一个控制器作为基础类,这样其他的控制器可以在其之上扩展;这个基础类可以包含一些通用的逻辑实现,它的子类就会重载这些实现代码,这种方法也有一定的缺陷,当有许多子类继承这个基础类,并大量地重用代码时,那么就有可能出现一个类的改变会影响到所有子类的情况。 5)用过滤器实现前控制器 过滤器提供了与用户请求的中心处理相类似的功能,也就是说,控制器的一些功能可以由过滤器来实现,这种方案的过滤器主要负责处理请求的截取和解释,而不是请求的处理和响应的生成;通常可以为应用系统提供一个核心控制点,以处理所有的系统服务和程序逻辑,核心控制也就表明了所有的请求都可以简单地被跟踪和记录,从而方便各种服务功能的实施;当然,它也存在一些缺点,一个核心控制点的小问题可能会引发系统的崩溃,但在应用系统的实际开发中,这并不是个问题,因为通常我们都会在同一个层面上实现多个控制器,从而避免了这个缺陷;在控制器中,开发人员可以很方便地实现一个检查安全机制的组件,从而可以在最外层屏蔽对系统的恶意访问,另外使用控制器也会提高系统模块的可重用性,尤其在控制器同时使用帮助类的时候。 4、视图帮助 视图帮助(View helper)是属于表示层的设计模式,一个视图帮助可以包含相关视图中的数据访问和内容显示的逻辑,并可以精炼简化视图;显示逻辑主要是关于如何格式化页面上的数据,而访问逻辑则是关于如何取出数据,视图帮助通常用来显示数据的JSP标记(tag)或是读取数据的JavaBean。 这种设计模式的出现主要是由于目前的应用系统通常需要实时地开发显示内容,并且能处理动态的程序数据。如果这些程序数据的访问逻辑和显示逻辑的关系过于紧密,则系统的表示层就会经常需要改动,从而系统的灵活性、重用性会大大地受到破坏;同时在相同的模块中实现访问逻辑和显示逻辑将会影响系统的模块化 |