UML软件工程组织

J2EE的MVC体系结构及其设计模式(二)
51CMM.COM原创 作者:务实

 5、会话面
  会话面(session facade)模式在合作的企业对象间调节操作,并将应用函数合成一个单一简单的界面;它减少了类之间合作的复杂性,并使得类的调用者在该类变化的时候无需改动,这种模式通常以一个会话bean实现,以用来隐藏底层ejb的复杂交互。
  这种设计模式出现的背景在于EJB通常既包括程序数据,又包括程序逻辑,而这些代码都会通过一定的界面作用于客户层,在多层次的J2EE平台应用程序中,就会造成一定的困难。
  具体来说,在J2EE平台上的多层次系统中,通常会存在以下的问题:
  (1)层次之间联系过于紧密,客户层和后端的业务对象具有较强的依赖关系;
  (2)在客户和服务器之间有多次方法调用,因而导致了Web性能方面的问题;
  (3)缺乏一定的客户访问机制,使得一些后台对象被随便访问。
  一个多层次的J2EE应用程序通常具有很多由EJB实现的服务器端对象,它们通常负责提供系统服务、数据信息等,也就是说作为业务对象,它们既包括相关的程序数据,也包括其程序逻辑;在J2EE应用系统中,负责程序逻辑的对象通常由会话bean实现,而表示持久性存储,并在多个用户间共享的对象则由实体bean来实现;当然,应用系统的用户需要访问企业对象来满足自己的需求,如果企业对象向用户提供接口,用户可以直接地与相关对象通信,但是这样一来,用户必须负责管理所调用的企业对象之间的关系,并且能够处理其间的业务流程;然而,如果用户和业务对象之间存在过于直接的交互,两者的联系就会过于紧密,同时也使得用户过于依赖企业对象的具体实现,并负责管理与交互过程有关的业务对象查找和创建,以及不同的对象间相互调用的关系,甚至一些时候用户还需要管理多次调用之间的事务管理环节。
  在用户需求不断增加时,这也是应用系统经常发生的情况,用户与不同的企业对象之间的交互也会变得越来越复杂,而企业对象可能需要一定内部的更新才能满足前者的需要,但是这样的话用户又需要根据企业对象实现的变化而做出相应的改变,这种情况将为应用系统带来相当大的麻烦;在访问EJB应用系统时,用户需要与远程对象进行交互。如果用户直接与所有相关的业务对象交互的话,将带来很大的Web负担;因为对于每一个ejb的激活,都将产生一次远程的调用,而如果存在大量的系统用户,用户与对象间的交互就将为Web通信带来很大的压力,使系统性能受到很大破坏;如果用户可以直接访问后端的企业对象,但是系统中又缺少一个统一的用户访问机制,那么这些访问很有可能变得杂乱无章,引起系统性能的下降,甚至导致一些安全问题。
  为了解决以上的问题,开发人员可以采用会话面的设计模式,即使用会话bean来实现一个面(facade)来包含一个工作流中所有相关对象的交互;这个会话面负责管理业务对象,并向用户提供一个统一的服务访问层,会话面可以面向底层对象的交互过程,并提供一个仅仅包含必须提供的接口的服务层,由此它将复杂的对象交互和用户之间隔离开来; 会话面也负责管理企业数据和企业对象之间的交互,并表达其中需要的企业逻辑,因此会话面也可以管理企业对象之间的作用关系;同时,根据工作流的需要,会话面也管理对象的创建、查找、修改和删除。
在一个复杂的应用系统中,会话面可以将其生命周期的管理下放到一个单独的帮助对象去,比如说,会话面可以将管理会话和实体bean生命周期的工作交给服务定位对象; 同时,在应用系统中,检查业务对象之间的作用关系也是非常重要的,一些关系可能是暂时的,即只使用于一定的交互过程,而另外一些关系则是永久的,暂时的关系适合建模于会话面中的工作流,永久的关系则需要具体情况具体分析。
  图6中的类图简要描述了会话面的设计模式,图7给出了会话面的序列表示,即参与组件及其交互关系。

  图6 会话面类图

  图7会话面序列图
  这里我们对于图7的各个组件加以简要的介绍:
  (1)客户(Client)。这表示会话面的客户,即需要访问相关企业服务的客户端应用程序,当然也可以是在同一层面或不同层面的另外一个会话bean。
  (2)会话面(Session Facade)。会话面通常是用会话bean来实现的,它管理着多个企业对象的作用关系并提供一个高层次的抽象界面给用户。
  (3)业务对象(Business Object)。业务对象是一个可以使用多个不同设计方案的对象,例如会话bean、实体bean和数据访问对象。在图6中业务对象负责提供数据和服务,而会话面则需要与多个业务对象实例交互而获得相应的服务。
  会话面实际上就是业务层的一个控制对象,它负责控制用户与企业数据和企业服务对象之间的交互;在一个复杂的应用系统中,甚至可能会有多个会话面作为用户和对象模块之间的中介。
下面介绍两种实现会话面的常见方法。
  (1)无状态的会话面
  在实现会话面的时候,首先应该决定是用状态化还是无状态的会话bean来实现,这主要取决于会话面所建模的业务流程;如果一个业务流程只需要一次方法调用就可以实现其服务,那么就可以使用无状态的会话bean来实现它。
  (2)状态化的会话面
  当一个业务流程需要多次方法调用来实现其服务时,开发人员最好使用状态化的会话bean来实现这一流程,因为每次方法调用的状态信息都必须在会话bean中保存。
  通过在应用系统中采用会话面的设计模式,将在系统中得到以下的收益:
  ①为用户提供一个简单的接口,并隐藏所有与系统组件复杂的交互过程;
  ②减少暴露给用户的企业对象,从而降低它们之间的依赖关系;
  ③向用户隐藏系统组件间的交互过程和依赖关系,从而使得系统更加容易管理,并提供相当的灵活性;提供一套统一的用户访问机制,便于管理用户对于系统服务的请求与访问。
  6、 数据访问对象
  数据访问对象(data access object,DAO)模式将数据访问逻辑抽象为特殊的资源,也就是说将系统资源的接口从其底层访问机制中隔离出来;通过将数据访问的调用打包,数据访问对象可以促进对于不同数据库类型和模式的数据访问。
  这种模式出现的背景在于数据访问的逻辑极大程度上取决于数据存储的格式,比如说关系型数据库、面向对象数据库、磁盘文件等。
  目前大部分的J2EE应用程序都需要在一定程度上使用可持久性的数据,而实现持久性数据的方法因应用程序不同而异,并且访问不同存储格式数据的应用程序接口(API)也有着显著的差别;有的时候,应用程序还会访问存储在不同操作平台上的数据,这使得问题更为复杂,通常,应用程序会使用共享的分布式组件,如实体bean来表达持久性数据。应用程序可以使用bean管理的持久性实体bean,而在实体bean中植人数据访问逻辑,或者使用容器管理的持久性实体bean,从而使容器管理所有的事务和持久性细节;而如果应用程序对于数据访问的需求十分简单的话,也可以采用会话bean或Servlet直接访问持久性存储来读取和修改数据。
  一些应用程序可以使用JDBC应用程序接口来访问关系数据库中的数据,JDBC负责一般的持久性数据访问和管理,在J2EE应用程序中,JDBC中可以嵌入SQL语句,用以访问关系型数据库,当然根据数据库类型的不同,SQL语句的词法和语法也会有所不同;需要说明的是,当数据存储格式不同的时候,数据访问逻辑的区别就更加明显了,例如关系型数据库、面向对象数据库和磁盘文件,各自数据的访问逻辑各有千秋,这样一来就造成了程序代码和数据访问代码之间的依赖关系;当程序组件,即实体bean、会话bean或servlet、JSP等需要访问数据源时,它们会使用正确的应用程序接口来得到连接并管理数据源,但这样也会造成这些组件与数据源物理实现之间的依赖关系,从而使得应用程序很难从一个数据存储实体移植到另一个数据存储实体中去;当数据源的物理实现变化的时候,应用程序也必须相应地加以改变。
  基于以上所讨论的问题,开发人员开始采用数据访问对象的方法。数据访问对象实际上就是包含对于所有数据访问逻辑的对象,并管理着对于数据源的连接,根据数据源的不同,数据访问对象实现了不同的访问机制,这里所说的数据源可以是持久性存储介质,如关系型数据库,也可以是外部服务,如B2B的数据交换;不仅是用户,而且包括应用系统中的其他组件,也可以使用数据访问对象所提供的数据访问接口,数据访问对象将数据源的物理实现细节与其用户完全分离开来,并且在底层数据源变化的时候,数据访问对象向用户提供的接口是不会变化的;这种方法使应用系统使用数据访问对象时可以适应多种数据存储介质,总之,数据访问对象就是系统组件和数据源中间的适配器。
  图8中的类图表示了数据访问对象设计模式的参与对象和之间的调用关系,图9是这种设计模式的序列图。

  图8 数据访问对象类图

  图9 数据访问对象序列图
  对于图9序列图中的组件加以解释如下:
  (1)业务对象(Business Object)。表示数据的用户,它需要对于数据的访问,一个业务对象可以用会话bean、实体bean或是其他Java程序来实现。
  (2)数据访问对象(Data Access Object)。数据访问对象是这种模式中的主题,它提供了底层数据访问的对象,并将其提供给业务对象以使得后者能够透明地访问数据源;同时业务对象也将数据的加载和存储操作移交给数据访问对象处理。
  (3)数据源(Data source)。这里指的是数据源的物理实现,这个数据源可以是一个数据库,包括关系型数据库、面向对象数据库或文件系统。
  (4)传输对象(Transfer Object)。这里的传输对象指的是数据载体。数据访问对象可以使用传输对象来向用户返回数据,而数据访问对象同样可以从用户那里得到传输对象来对数据源中的数据进行更新。
  下面给出几种实现数据访问对象设计模式的方法。
  (1)自动数据访问对象代码的生成
  既然每一个业务对象都对应于一个数据访问对象,那么开发人员就可以建立业务对象、数据访问对象和底层实现的关系;一旦这种关系建立起来,开发人员就可以为所有的数据访问对象编写特殊的代码生成工具。
  生成数据访问对象的信息通常存储在一个开发人员定义的描述文件中,如果对于数据访问对象的要求过于复杂,开发人员可以考虑使用第三方工具来为关系型数据库提供对象对关系的映射。这些工具通常是一些GUI程序,可以用来将业务对象映射为持久性的存储对象,并定义中间运作的数据访问对象,在映射完成的时候,这些工具可以自动地生成代码,并提供一些相应的功能,如缓存结果、缓存查询、与应用服务器整合、与第三方产品整合等。
  (2)数据访问对象代理(Factory for Data Access Objects)
当底层的数据存储不会轻易改变的时候,开发人员可以采取这种方法来实现相应的,数据访问对象,图10是这种方法的类图。

  图10 使用DAO代理类图
  当底层的数据存储可能会变化的时候,开发人员可以采用抽象代理的方法来实现数据访问对象;抽象代理的方法会创建一些虚拟的数据访问对象代理和各种类型的实际数据访问对象代理,每种对象对应一种持久性存储介质的实现,一旦组件得到这些代理,就可以利用来创建需要使用的数据访问对象。
  图11给出了这种情况的类图。该类图表示了一个基础的数据访问对象代理,它是一个抽象类,被其他一些实际的数据访问对象代理继承以支持特定的数据访问函数;用户可以得到一个实际的数据访问对象,并利用它来创建需要的数据访问对象而访问相关的数据,每一个实际的数据访问对象都负责建立对于数据源的连接,并得到和管理所支持的业务数据。

  图11 抽象代理使用DAO

  下图12是这种情况下的序列图。
  图12抽象代理使用DAO序列图
  这种设计模式的优势:
    透明性好。业务对象可以在不知道数据源实现细节的情况下访问数据。由于一切数据访问细节被数据访问对象所隐藏,所以这种访问过程是透明的。
    可移植性好。在应用系统中添加数据访问对象,可以使得前者能够很方便地移植到另外一种数据库实现上。业务对象与数据实现是隔离的,所以在移植过程中,仅仅对数据访问对象进行一些变化即可。
    减少业务对象的代码复杂度。由于数据访问对象可以管理所有的数据访问复杂细节,这也就简化了业务模块和其他数据客户的代码。同时也提高了应用系统的整体可读性和开发率。
    集中处理所有数据访问。由于所有的数据访问操作都移交给数据访问对象,这样应用系统其他部分就与数据访问实现隔离开来,而全部相关操作都与数据访问对象集中处理,这样也使得相关操作更加容易被维护和管理。
这种设计模式的缺陷:
    对于容器管理的持久性不能利用。如果EJB容器采取容器管理的方式,那么所有对于持久性数据存储的管理都由容器负责。这样的话应用系统就无需实现数据访问对象了,因为应用服务将透明地提供这一功能。
    添加了额外的层面。数据访问对象在数据用户和数据源之间添加了一个层面,也就增加了一些额外的设计和实现的负担。当然,我们认为它是物有所值的。
总之,在开发人员选择不同模式的时候,应该注意,一定的模式对应于一定的应用层次。比如说,与视图和显示相关的模式就是在Web层应用的。而一些与业务逻辑控制相关的模式则是与EJB层次相关的。另外一些关于读取数据和分派操作的模式则适用于不同的层次之间。

 
 

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