UML软件工程组织

解析J2EE型式的应用(上)
作者:谷和启(选自赛迪网)
一、概述

许多实际开发软件的人都没有时间始终跟踪注意有哪些关于设计和体系结构的言谈,即使他们有时间,他们也是希望从中找出一些具体的应用以帮助他们在下一次焉设计系统的时候可以做出更明智的选择。型式(pattern)是一个良好的体系结构和设计信息来源,可以训练软件设计者。

在许多专业水平的规则中,有一条关键的规则是不要低水平的重复。目前设计领域的一些实际情况,也就是一项设计大部分是在相关上下文环境中已有理想应用的综合。没有一个软件设计师采用的是全新的一套思想来生成软件系统;关键是把这些知识都汇集起来,以便于所有软件设计师都可以生成更好的系统。来自Sun公司的Bill Joy的说法,表明并不是所有良好的思想都来自Sun公司内部,因此人们必须对其他领域打开自己的思想。幸运的是,软件开发者越来越注意分享他们的思想,在开放源代码(Open Source) 社团中,人们还共享代码。这种在代码和思想上合作的趋势促成了软件设计型式(pattern)目录的产生,这些内容可供公共使用,并且可以帮助人们设计各种不同的软件系统。

一个型式就是在一种给定上下文环境下已经证实的解决方案。具体环境越宽,对应的型式适用的面就越广。在软件术语中,型式实际上指人们在实践中获得的“经验总结”,指出在指定、设计和实现软件系统时哪些工作效果最好。

在许多软件和系统领域都可以找到型式。在高层,人们在执行特定领域的分析时可以找到型式。在这种分析中发现的实体和关系将在一个业务方面反复出现。这种重复性使人们发现了相应的型式。如果你在某个特定领域工作,如金融或者电信,则调查一下现有的具体领域的型式可以节省时间和精力。型式也可以是某种特定技术或者语言专用的(有时称为“惯用语”)。Java专用的型式在语言惯用语的各级中都存在。

二、J2EE型式的应用

对于J2EE型式,可能对此最突出的体现就是由Sun Java Center的一些Java设计师所做的工作。他们已经根据Sun公司Professional Services(专业服务)人员多年基于J2EE的实际系统实现生成了一组专门用于J2EE的型式。这组型式位于在线的Java Developer Connection(Java开发者连接)中,并且正在通过J2EE Patterns电子邮件群发展和变化。

Sun Java Center的J2EE型式针对的就是n层业务系统,并且根据驻留的层而分类为:Presentation、Business和Integradon。下表1显示了此分类中的一些更常见的示例型式。

这个列表只是Sun Java Center中提供的J2EE型式的一部分,J2EE型式也是J2EE Blueprints 的组成部分。提供的这些型式实例经过证实都可以在J2EE系统平台上工作,这是对设计者的极大帮助。我们可以从别人的经验中学习,并且观察他们如何为自己的环境实现相关的型式。 我们不能只使用J2EE专用的型式或者其他任何型式,它们就像一堆积木,简单地复制和粘贴这些代码形成自己的解决方案而不更改任何代码是不好的。有经验的设计师将把一个型式作为一个总体指导使用,让它符合特定上下文环境的需要。

所有的应用程序上下文环境都有一定程度的惟一性,因此这些型式的实现必须经过调整以满足我们特定的要求。同时,一组型式肯定无法覆盖我们整个应用程序的要求。我们应该把型式看作为一组“设计时使用的”组件,可以经过调整然后通过自定义的逻辑结合起来(它本身是可以调整的)而得到最终的产品。

表1 J2EE型式应用



1、前端控制器型式

为用户生成显示的视图应该包含最少的业务代码,以便于在多个视图中共享以及可以独立于具体的视图而更改。这些规律也适用于为视图提供普通服务的代码以及在视图之间提供工作流和导航的代码。普通服务如安全性和状态管理,不应在多个视图之间复制,因为这样会带来系统维护方面的问题和一致性问题。与一个应用程序的某部分关联的工作流,如进行一个在线购物的一系列步骤,当控制其相关导航的代码分在多个视图中的时候将更难被改变。

Front Controller(前端控制器)型式引入了一个组件,它捕获客户请求并且进行下列一项或者多项处理:

●应用普通服务,如验证和访问控制。

●决定处理请求的适当视图。

●通过处理用户令牌和访问的数据源为相关请求建立状态信息。

图1显示了一个前端控制器如何实现一个客户和多个视图之间的中介。这种中介可能是应用程序中一个工作流的一部分,也可以是在语言或者其他因素基础上的一个选择。



图1


一个前端控制器可以与其他组件或者帮助器(helper)交互以提供要求的服务。前端控制器使用一个分离的分配器组件来实现要求的任何工作流也是常见的情况。它还将使用帮助器(如View Helper即视图帮助器型式)来执行与业务有关的处理或者把状态信息传递给视图。图2所示的情况说明了这些组件之间的交互。



图2


2、复合视图型式

大多数基于Web的系统由许多不同的网页或者视图构成。每个视图都将包括一些专用的功能,如同时可供选择的部分产品列表,以及普通的导航、信息或者功能化元素。如果对于这些元素的代码和格式在多个使用它的视图中都重复,则系统会非常难于更新和维护,因为任何修复和更改都必须在相关代码和格式处理出现的地方应用。

作为一种解决办法,复合视图(Composite View)型式定义了各种阶段以有效地把一个用户的接口划分成多个子视图,并且可以被重新结合起来以生成需要的总体视图。每个子视图构成一个单独的组件,可以与其他子视图分开维护、更新和增强。构成复合视图型式的一个示例Web网页。在这里我们设计在屏幕顶部有一个Header View(标题视图),在这个标题下方和网页的左侧有导航视图,当然还有居中显示的Main Body(正文)视图。复合视图的总体构成可以使用图3所示的其他视图。



图3


视图管理器可以包含在复合视图和子视图之间。一个视图管理器的使用是可选的,但如果要求有条件地包含一些内容,则它会有用。作为一个JSP网页实现而不包含一个视图管理器的简单复合视图实现,如下:


<table border="0" valign="top" width="100%">
    <tr>
    <td><jsp:include page="templates/header.jsp"/></td>
    </tr> 
    <tr>
    <td><jsp:include page="tenlolates/navigation.jsp"/></td>
    </tr>
    <tr>
    <td><jsp:include page="content/java_book_list.jsp"></td>
    </tr>
    </table>


3、会话正面型式

如果EJB简单地用作业务数据的存储或者简单的业务服务,那么大多数业务逻辑都将仍然驻留在使用这些BJB的客户上。这样做是有害的,原因有两方面。首先,它将再次带来过量的网络访问,因为客户要访问很详细筛选的业务服务和数据。它还会把客户强烈地联系在业务处理中。这样在客户之间造成了不必要的业务代码分散和重复。

解决的办法是采用正面(Facade)型式的一种变形,正面(Facade)是指一个对象或者组件,它被引入到客户和一个复杂的子系统之间。这个正面只展示客户要求的服务以及相关的综合服务,这样可以提供粗选的相应服务(不是细选)。在J2EE型式术语中,会话正面(Session Facade)为业务逻辑和多个EJB封装的服务执行这个角色。会话正面,如其名字所示,采取的是一个会活EJB的形式。客户与会话正面通信,会话正面再根据其他EJB如实体bean来提供业务服务。

图4显示了一个会话正面如何控制对多个实体bean的访问并且提供一个对客户统一的接口。会话正面虽然一般用作基层实体EJB的一层掩护,但一个会话正面既可以从其他会话EJB访问服务和数据,也可以从数据访问对象(Data Access Objects)来访问。这些类之间的关系如图4所示。



图4


通常,会话正面会为一个或者多个业务使用案例封装相关功能。通过对该正面的一次调用可以得到多个业务操作(这种情况有时称为批处理方法分布式型式/惯用语)。客户想要执行的操作不是在返回一组值对象(Value Objects)的一个会话bean上的操作,而是可以移植到会话正面中。接着发生的是在服务器上迭代处理数据,只把结果传送回客户。这样就减少了网络传输量,当然也给服务器处理带来了一些负担。

4、服务定位器型式

从代码中看,在一个EJB的业务接口上使用方法带来的负担相对较小,只需要处理远程异常而已。但是EJB的生成需要有专门的基于JNDI的代码来发现主接口并且生成需要的EJB。这就迫使客户要包含相关代码以处理上下文环境的牛成、查找并且缩小引用的范围。同时,任何其他的复杂化如主接口引用的缓冲存储,必须被每个客户重复。

服务定位器(Service Locator)型式定义了一个对象可以如何执行与多个客户关联的多个EJB的查找和生成任务。客户只是简单地找到服务定位器,并且请求对需要的EJB的一个引用。所有与JNDI和EJB主接口的交互都被分配到了服务定位器。图5所示即为客户、服务定位器和EJB主实现和业务实现之间的交互。



图5


注意,服务定位器典型情况下是单独实现的,目的是共享缓冲存储带来的效益。

5、值对象型式

简单的数据对象通常把它们的数据作为属性展示出来。一个客户将使用获取器或者设置器在需要的时候访问这些属性。与过程中(in-process)的方法调用相关的相对较低的负荷已经使这种处理成为一种普通的实践,特别是在像集成开发环境(Integrated Development Environments,IDE)这样的“拖放-点击”环境中根据JavaBean生成用户接口。但是,—旦在客户和数据对象之间引入了一个网络,这种基于属性的编程会产生不好的“锯齿效果”,因为有数据在持续地通过网络传送。出现这种情况时,通信过程就成为整个计算的主导,大多数进行数据访问的时间都花在等待网络调用返回的信息,而网络性能也会由于传输的数据量太大而下降。

在访问EJB展示的数据或者以数据为中心的服务时,这种问题就会表现出来。如果需要的数据分布在多个EJB上则产生的效率就会被放大,因为每一部分都必须通过网络来分别访问。这里要考虑的另一方面是大多数数据访问都是用于读,而不是写操作。

这些问题可以通过生成一个值对象(Value Object)来解决。值对象把业务数据封装在一个普通的Java对象中,而不是像EJB这样的重型分布式对象。这里不需要为EJB的每个属性各发出一个请求,而是可以只发出一个返回值对象的请求。值对象将被回送给客户,一般是通过Java串行化。接着客户在其本地地址空间中访问值对象的属性,从而节省许多网络上的传输。EJB及其值对象之间的这种关系如图6所示。



图6


客户、EJB和值对象之间的交互如图7所示。



图7


根据应用程序的要求,我们可以使用不同的变化形式。值对象只能封装相应EJB表示的部分业务数据,它是可以更新的,把更改的情况回传到其父级EJB;或者如果需要有非Java互操作能力,值对象可以采用一个XML文档的形式。 值对象可以在适当的时候用于实体EJB、会话EJB和数据访问对象。

6、业务委派型式

客户直接与业务服务交互并不是一个好的想法。这使他们在实现中面临潜在的变化。通过应用会话正面(Session Facade)型式把与业务服务的一些交互封装在一个EJB中是可能的。即使如此,客户仍然要处理查找、实例化以及管理一个EJB所需的远程出错处理。业务层的处理如果其复杂性有了任何变化,如缓冲存储和批处理调用,都需要由客户来完成。

作为一种解决方案,业务委派(Business Delegate)型式可以作为一个业务服务的客户方抽象使用。它可以潜在地直接与各业务组件协同工作,或者可以作为客户方对一个会话正面的网关来使用。业务委派型式可以负责所有的专门EJB交互并且为客户提供一个本地接口。这个接口可以提供一些方法用于封装多个服务器交互。业务委派型式还可以把远程异常映射到有意义的应用程序异常。

业务委派型式是执行客户方业务信息缓冲存储的逻辑位置,如处理值对象或者重试失败的调用以及对不同服务器的故障恢复。客户,业务委派和业务对象之间的关系如图8所示。



图8


图8中所示的服务定位器是另一个型式,可以独自使用也可以与一个业务委派型式结合起来使用。同时,我们的目的是把处理命名服务的复杂性隐藏起来,把缓冲存储和优化添加到对业务对象及其工厂的引用检索中。【未完待续】

 
 

版权所有:UML软件工程组织