软件项目实训及课程设计指导——如何应用数据访问服务层分离业务层和持久层之间耦合关系
作者已经在本系列文章《软件项目实训及课程设计指导--如何正确地设计J2EE应用系统持久层中的各个组件结构及关系》中为读者介绍了为什么要设计和应用数据访问服务接口的目的及如何设计该接口以真正达到利用数据访问服务层组件隔离业务处理逻辑和数据访问操作逻辑的应用效果。作者将在本文为读者介绍如何应用数据访问服务层分离业务层和持久层之间关系。
1、数据访问服务层和数据访问服务组件
J2EE系统平台技术规范为开发复杂的、分布式企业级的应用系统定义了一套体系结构设计模板和技术规范,它不仅提供了一套完整的基于标准化模块的功能服务组件,而且也提供了对企业软件应用系统的标准纵向分层设计方案。
如下示图为在J2EE技术平台下的软件应用系统的典型的五层分层设计方案,在该分层设计中的系统各个层之间只存在单向依赖关系,从而较好地实现了各个层的封装和彼此间的隔离。
这样的分层设计方案是有别于经典的三层架构体系结构和MVC体系架构等设计方案,它特别适宜于分布的应用环境或者数据操作访问复杂的软件应用系统的体系架构设计中,其主要的特色之处在于提供了一个"数据服务层"(DAOService)以进一步分离业务层和持久层之间的耦合关系。而通过数据访问服务层内的各个数据访问服务组件内的数据访问服务功能方法为上层的业务层组件提供统一的数据访问功能服务,保持业务层内的功能组件的业务处理实现的"纯洁性"!
2、数据访问服务层中的数据访问服务组件在软件应用系统中存在的必要性
(1)首先,可以提高软件应用系统中业务层组件的可重用性
利用数据访问服务组件(简称为DAOService组件)隔离软件应用系统中的业务处理逻辑和数据访问操作逻辑,在各个业务逻辑处理组件中只需要与数据访问服务组件进行交互,而不再需要与不同的DAO组件进行具体的交互——因为DAO组件是软件应用系统中数据访问的基本功能组件,它们完成对物理数据库系统数据库表的基本操作,如提供对数据库表中的数据进行增、删、改和查询等方面的功能方法。
这样的设计方案可以降低整个软件应用系统中的业务逻辑处理层和持久层中的数据访问组件(DAO组件)之间的藕合度,将使得业务层组件的可重用性得到进一步地提高。从如下示例图所体现出的数据访问服务组件与上层业务层和下层的持久层之间关系的UML类图中可以了解到,软件应用系统中的业务处理功能类并没有直接依赖某种形式的数据源的数据访问功能操作,而是依赖数据访问服务接口。从而隔离了软件应用系统中的业务处理功能类对具体的数据源的依赖,也就提高了软件应用系统的灵活性和对数据源的适应性。
(2)其次,可以作为软件应用系统中业务层组件和数据访问操作组件的中介
企业软件应用系统中经常会出现复杂的数据访问操作逻辑,这样将不可避免地会出现各种复杂的SQL语句及相关的程序代码,而这些复杂的SQL语句可以在数据访问服务层中的有关的数据访问服务组件内的功能方法中最终拼接而形成。如下示图为示例项目银行账户信息管理系统中转账方法的部分示例代码的局部截图,其中的SQL语句接收相关的工作参数。
另一方面,持久层中的各个DAO组件内的相关功能方法一般只负责对单一数据库表的数据访问逻辑,而跨多个不同的数据库表的数据访问操作一般则由数据访问服务组件内的相关方法完成以有利于事务控制管理,这样能够最大程度地重用持久层中的DAO组件、同时也简化了事务管理和控制的编程实现。
下图所示的UML类图为示例项目银行账户信息管理系统中的UserDAOServiceImple数据访问服务组件与代表用户信息的DAO组件、代表管理员信息的DAO组件和代表城市信息的DAO组件之间关系图示,在UserDAOServiceImple类中实现跨数据库表的数据访问操作。
而下示例图所示的代码片段是对上图的功能要求的具体实现,为了能够避免UserDAOServiceImple数据访问服务组件依赖于各个具体的DAO组件的实现类,依据依赖倒置设计原则应该将UserDAOServiceImple类改为依赖于持久层中的各个DAO组件的接口。
3、利用数据访问服务层组件隔离业务处理逻辑和数据访问操作逻辑
(1)在软件应用系统项目中重视对业务服务层的应用
在企业应用系统的体系架构设计中,设计人员常常忽视对软件应用系统中的业务服务层的应用,不是将大部分的业务处理或者数据访问逻辑的代码放在软件应用系统的表现层页面中,就是喜欢直接在数据访问层的DAO组件中编写系统中的业务逻辑处理的代码。
这样的设计方案,不仅违背了面向对象OOP类设计中的"单一职责"的设计原则,而且也将会导致出现紧耦合的程序类之间的关系。
(2)违背OOP类设计中的"单一职责"和"纵向分层"设计原则的代码示例
如下示例中所示的程序代码示例,由于在代表系统控制处理层的J2EE Servlet组件代码中直接出现本应该位于持久层相关组件方法内的SQL语句、以及直接应用JDBC API操作访问本应该由持久层内的DAO组件方法实现的数据访问功能,这是不良好的程序类之间关系设计的一个常见的错误示例——违背"单一职责"设计原则的代码示例。
首先,这样的设计结果将导致Servlet组件内的功能方法承担过多的"职责"——控制调度、数据分发、操作访问数据和转发最终的操作返回结果数据等方面功能,而其中的部分"职责"本应该由业务层内组件和持久层内组件所承担,这将使得Servlet组件内的功能方法的实现代码过于"臃肿"和不便于后期的维护和升级完善等工作。
其次,这样的设计结果将使得系统控制处理层、业务层和持久层三者紧密耦合,没有遵守J2EE 应用系统平台中所倡导的"纵向分层、横向分块、多点分布"的设计原则。
public class UserInfoServlet extends HttpServlet{ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // … 其他的数据处理和功能代码在此省略 try { ConnectionMySQL con=new ConnectionMySQL(); Connection c=con.connectionMySQL(); Statement stmt = c.createStatement(); ResultSet res = stmt.executeQuery("select * from useInfo where id='"+userID+"'"); // … 其他的数据处理和功能代码在此省略 } catch(Exception e) { // … 异常处理的功能代码在此省略 } //… 其他的数据处理和功能代码在此省略 } //… 其他方法的功能实现代码在此省略}
对于数据访问服务层组件相关的更多的编程技术及相关的功能程序代码示例,请读者阅读作者的《J2EE项目实训——UML及设计模式》一书中的第7章"架构设计中的架构模式"章节中的有关内容。



