`
justin8335
  • 浏览: 28911 次
  • 性别: Icon_minigender_1
  • 来自: 福州
社区版块
存档分类
最新评论

常见SSH的架构设计策略(二)

阅读更多
Rich Domain Object模式

在这种模式下,Domain Object不再是单纯的数据载体,Domain Object包含了相关的业务逻辑方法。例如News类包含了addNewsView 方法等。

下面是修改后的News类的源代码:

java 代码
  1. public class News extends BaseObject   
  2.   
  3. {   
  4.   
  5.     //此处省略了其他的属性   
  6.   
  7.     //此处省略了属性对应的setter和getter方法   
  8.   
  9.     //增加新闻回复的业务逻辑方法   
  10.   
  11.     public NewsReview addNewsReview(String content)   
  12.   
  13.     {   
  14.   
  15.         //以默认构造器创建新闻回复实例   
  16.   
  17.           NewsReview review = new NewsReview();   
  18.   
  19.         //设置回复内容   
  20.   
  21.           review.setContent(content);   
  22.   
  23.         //设置回复的发布日期   
  24.   
  25.           review.setPostDate(new Date());   
  26.   
  27.         //设置回复的最后修改日期   
  28.   
  29.           review.setLastModifyDate(new Date());   
  30.   
  31.         //设置回复与消息的关联   
  32.   
  33.           review.setNews(this);   
  34.   
  35.           return review;   
  36.   
  37.     }   
  38.   
  39.     //此处省略了重写的hashCode,equals等方法   
  40.   
  41. }   
  42.   

在上面的Domain Object中,包含了相应的业务逻辑方法,这是一种更完备的建模方法。

注意:不要在Domain Object中对消息回复完成持久化,如需完成持久化,必须调用DAO组件;一旦调用DAO组件,将造成DAO对象和Domain Object的双向依赖;另外,Domain Object中的业务逻辑方法还需要在业务逻辑组件中代理,才能真正实现持久化。

在上面的业务逻辑方法中,并没有进行持久化。如果抛开DAO层,这种Domain Object也可以独立测试,只是没有进行持久化。

DAO对象是变化最小的对象,它们都是进行基本的CRUD操作,在两种模型下的DAO对象没有变化。

另外还需要对业务逻辑对象进行改写,虽然Domain Object包含了基本业务逻辑方法,但业务逻辑对象还需代理这些方法,修改后业务逻辑对象的代码如下:

java 代码
  1. public class FacadeManagerImpl implements FacadeManager   
  2.   
  3. {   
  4.   
  5.     //业务逻辑对象依赖的DAO对象   
  6.   
  7.     private CategoryDAO categoryDAO;   
  8.   
  9.     private NewsDAO newsDAO;   
  10.   
  11.     private NewsReviewDAO newsReviewDAO;   
  12.   
  13.     private UserDAO userDAO;   
  14.   
  15.     //...此处还应该增加依赖注入DAO对象必需的setter方法   
  16.   
  17.     //...此处还应该增加其他业务逻辑方法   
  18.   
  19.     //下面是增加新闻回复的业务方法   
  20.   
  21.     public NewsReview addNewsReview(Long newsId , String content)   
  22.   
  23.     {   
  24.   
  25.         //根据新闻id加载新闻   
  26.   
  27.           News news = newsDao.getNews(newsId);   
  28.   
  29.         //通过News的业务方法添加回复   
  30.   
  31.         NewsReview review = news.addNewsReview(content);   
  32.   
  33.         //此处必须显示持久化消息回复   
  34.   
  35.           newsReviewDAO.saveNewsReview(review);   
  36.   
  37.           return review;   
  38.   
  39.     }   
  40.   
  41. }   
  42.   

在Rich Domain Object的模型中,addNewsReview方法将放在News类中实现,而业务逻辑对象仅对该方法进行简单的代理,执行必要的持久化操作。

在这里存在一个问题:业务逻辑方法很多,哪些业务逻辑方法应该放在Domain Object对象中实现,而哪些业务逻辑方法完全由业务逻辑对象实现呢?Rod Johnson认为,可重用度高,与Domain Object密切相关的业务方法应放在Domain Object对象中实现。

业务逻辑方法是否需要由Domain Object实现的标准,从一定程序上说明了采用Rich Domain Object模型的原因。由于某些业务方法只是专一地属于某个Domain Object,因此将这些方法由Domain Object实现,能提供更好的软件复用,能更好地体现面向对象的封装性。

Rich Domain Object模型的各组件之间关系大致如图8.2所示(贫血模式的组件关系图与此类似)。

图8.2  Rich Domain Object的组件关系图

这种Rich Domain Object模型主要的问题是业务逻辑对象比较复杂,由于业务逻辑对象需要正面封装所有的DAO对象,因而难免有大量的DAO方法(基本的CRUD)需要业务逻辑对象封装。业务逻辑对象封装DAO方法主要基于如下考虑:

—  DAO对象不应该暴露为Web层。

—  DAO对象的DAO方法必须增加事务控制代码,而事务控制则放在业务逻辑层完成。

为了简化业务逻辑对象的开发,Rich Domain Object模型可以有如下两个方向的改变:

— 合并业务逻辑对象与DAO对象。

— 合并业务逻辑对象和Domain Object。

1.合并业务逻辑对象与DAO对象

在这种模型下DAO对象不仅包含了各种CRUD方法,而且还包含各种业务逻辑方法。此时的DAO对象,已经完成了业务逻辑对象所有任务,变成了DAO对象和业务逻辑对象混合体。此时,业务逻辑对象依赖Domain Object,既提供基本的CRUD方法,也提供相应的业务逻辑方法。

下面是这种模式的代码(Domain Object的实现与前面的Rich Domain Object模式一样,此处不再给出):

java 代码
  1. // NewsServiceHibernate继承HibernateDaoSupport,实现NewsService接口   
  2.   
  3. public class NewsServiceHibernate extends HibernateDaoSupport    
  4.   
  5. implements NewsService   
  6.   
  7. {   
  8.   
  9.     //此处添加NewsService对象依赖的DAO对象,以及对应的setter方法   
  10.   
  11.     //根据主键加载消息   
  12.   
  13.     public News getNews(Long id)    
  14.   
  15.     {   
  16.   
  17.           News news = (News) getHibernateTemplate().get(News.class, id);   
  18.   
  19.           if (news == null) {   
  20.   
  21.                throw new ObjectRetrievalFailureException(News.class, id);      
  22.   
  23.           }   
  24.   
  25.         return news;   
  26.   
  27.     }   
  28.   
  29.     //保存新的消息   
  30.   
  31.     public void saveNews(News news) {   
  32.   
  33.           getHibernateTemplate().saveOrUpdate(news);   
  34.   
  35.     }   
  36.   
  37.     //根据主键删除消息   
  38.   
  39.     public void removeNews(Long id)   
  40.   
  41.     {   
  42.   
  43.           getHibernateTemplate().delete(getNews(id));   
  44.   
  45.     }   
  46.   
  47.     //查找全部的消息   
  48.   
  49.     public List findAll()   
  50.   
  51.     {   
  52.   
  53.         getHibernateTemplate().find("from News"));   
  54.   
  55.     }   
  56.   
  57.     //下面是增加新闻回复的业务方法   
  58.   
  59.     public NewsReview addNewsReview(Long newsId , String content)   
  60.   
  61.     {   
  62.   
  63.         //根据新闻id加载新闻   
  64.   
  65.           News news = newsDao.getNews(newsId);   
  66.   
  67.         //通过News的业务方法添加回复   
  68.   
  69.         NewsReview review = news.addNewsReview(content);   
  70.   
  71.         //此处必须显示持久化消息回复   
  72.   
  73.           newsReviewService.saveNewsReview(review);   
  74.   
  75.           return review;   
  76.   
  77.     }   
  78.   
  79. }   
  80.   

正如上面见到的,DAO对象和业务逻辑对象之间容易形成交叉依赖(可能某个业务逻辑方法的实现,必须依赖于原来的DAO对象)。当DAO对象被取消后,业务逻辑对象取代了DAO对象,因此变成了一个业务逻辑对象依赖多个业务逻辑对象。而每个业务逻辑对象都可能包含需要多个DAO对象协作的业务方法,从而导致业务逻辑对象之间的交叉依赖。

业务逻辑对象和DAO对象合并后的组件关系如图8.3所示。

图8.3  合并DAO对象和业务逻辑对象

这种模型也导致了DAO方法和业务逻辑方法混合在一起,显得职责不够单一,软件分层结构不够清晰。此外,使业务逻辑对象之间交叉依赖,容易产生混乱,未能做到彻底的简化。

2.合并业务逻辑对象和Domain Object

在这种模型下,所有的业务逻辑都应该被放在Domain Object里面,而此时的业务逻辑层不再是传统的业务逻辑层,它仅仅封装了事务和少量逻辑,完全无需DAO对象的支持。而Domain Object依赖于DAO对象执行持久化操作,此处Domain Object和DAO对象形成双向依赖,这种设计在某些地方也被称为充血模式,但有时会带来相当大的危险。

在这种设计模式下,几乎不再需要业务逻辑层,而Domain Object则依赖DAO对象完成持久化操作,下面是在这种模式下的News类代码:

java 代码
  1. public class News extends BaseObject   
  2.   
  3. {   
  4.   
  5.     //此处省略了其他的属性。   
  6.   
  7.     //此处省略了属性对应的setter和getter方法   
  8.   
  9.     //增加新闻回复的业务逻辑方法   
  10.   
  11.     public NewsReview addNewsReview(String content)   
  12.   
  13.     {   
  14.   
  15.         //以默认构造器创建新闻回复实例   
  16.   
  17.           NewsReview review = new NewsReview();   
  18.   
  19.         //设置回复内容   
  20.   
  21.           review.setContent(content);   
  22.   
  23.         //设置回复的发布日期   
  24.   
  25.           review.setPostDate(new Date());   
  26.   
  27.         //设置回复的最后修改日期   
  28.   
  29.           review.setLastModifyDate(new Date());   
  30.   
  31.         //设置回复与消息的关联   
  32.   
  33.           review.setNews(this);   
  34.   
  35.         //直接调用newsReviewsDao完成消息回复的持久化。   
  36.   
  37.         newsReviewsDao.save(review);   
  38.   
  39.           return review;   
  40.   
  41.     }   
  42.   
  43.     //此处省略了重写的hashCode,equals等方法   
  44.   
  45. }   
  46.   

从上面代码中可以看到,由于Domain Object必须使用DAO对象完成持久化,因此Domain Object必须接收IOC容器的注入,而Domain Object获取容器注入的DAO对象,通过DAO对象完成持久化操作。

合并业务逻辑对象和Domain Object后各组件的关系如图8.4所示。

这种模型的优点是:业务逻辑对象非常简单,只提供简单的事务操作,业务逻辑对象无须依赖于DAO对象。

但这种模型的缺点也是非常明显的:

—  DAO对象和Domain Object形成了双向依赖,其复杂的双向依赖会导致很多潜在的问题。

— 业务逻辑层和Domain层的逻辑混淆不清,在实际项目中,极容易导致架构混乱。

— 由于使用业务逻辑对象提供事务封装特性,业务逻辑层必须对所有的Domain Object的逻辑提供相应的事务封装,因此业务逻辑对象必须重新定义Domain Object实现的业务逻辑,其工作相当烦琐。

图8.4  合并业务逻辑组件和Doamin Object

8.4.3  抛弃业务逻辑层

在Rich Domain Object模型的各种变化中,虽然努力简化业务逻辑对象,但业务逻辑对象依然存在,依然使用业务逻辑对象正面封装所有的业务请求。下面介绍更彻底的简化即,彻底放弃业务逻辑层。

抛弃业务逻辑层也有两种形式:

—  Domain Object彻底取代业务逻辑对象。

— 由控制器直接调用DAO对象。

1.Domain Object完全取代业务逻辑对象

这种设计模式是充血模式更加激进的演化。由于在充血模式中业务逻辑对象的作用仅仅只提供事务封装,业务逻辑对象存在的必要性不是很大,因此考虑对Domain Object的业务逻辑方法增加事务管理,而Web层的控制器则直接依赖于Domain Object。

这种模型更加简化,使Domain Object与DAO对象形成双向依赖,而Web层的控制器直接调用Domain Object的业务逻辑方法。这种模型在有些地方也被称为胀血模式。

这种模型的优点是:分层少,代码实现简单。

但这种模型的缺点也很明显:

— 业务逻辑对象的所有业务逻辑都将在Domain Object中实现,势必引起Domain Object的混乱。

—  Domain Object必须向Web层直接暴露,可能导致意想不到的问题。

这种模型与充血模式的缺点相同:Domain Object必须配置在Spring容器中,接受Spring容器的依赖注入。

在这种架构模型下,Domain Object相当不稳定。如果业务逻辑需要改变,Domain Object也需要发生改变,而DAO对象与Domain Object形成双向依赖,这将导致从底层的Domain Object和DAO对象的修改,使这种架构模式的分层完全失去意义。各层之间以强耦合方式组合在一起,各层对象互相依赖,牵一发而动全身,几乎是最差的一种策略。

2.控制器完成业务逻辑

在这种模型里,控制器直接调用DAO对象的CRUD方法,通过调用基本的CRUD方法,完成对应的业务逻辑方法。这种模型下,业务逻辑对象的功能由控制器完成。事务则推迟到控制器中完成,因此对控制器的execute方法增加事务控制即可。

对于基本的CRUD操作,控制器可直接调用DAO对象的方法,省略了业务逻辑对象的封装,这就是这种模型的最大优势。对于业务逻辑简单(当业务逻辑只是大量的CRUD操作时)的项目,使用这种模型也未尝不是一种好的选择。

但这种模型将导致控制变得臃肿,因为每个控制器除了包含原有的execute方法之外,还必须包含所需要的业务逻辑方法的实现。极大地省略了业务逻辑层的开发,避免了业务逻辑对象不得不大量封装基本的CRUD方法的弊端。

这种模型也有其缺点:

— 因为没有业务逻辑层,对于那些需要多个DAO参与的复杂业务逻辑,在控制器中必须重复实现,其效率低,也不利于软件重用。

—  Web层的功能不再清晰,人为复杂化。Web层不仅负责实现控制器逻辑,还需要完成业务逻辑的实现,因此必须精确控制何时调用DAO方法控制持久化。

— 扩大了事务的影响范围。大部分情况下,只有业务逻辑方法需要增加事务控制,而execute方法无须增加事务控制。但如果execute方法直接调用了DAO对象的CRUD方法,则会导致这些方法不在事务环境下执行。为了让数据库访问都在事务环境下进行,因此不得不将事务范围扩大到整个execute方法。

本章小结

本章首先介绍了笔者在架构设计方面一些经验,从企业应用开发面临的困难讲起,并讲解了面对这些困难时应该采用何种应对策略。

其次介绍了常用的代理模式的使用,并深入介绍了由此衍生出来的Spring AOP框架。

最后重点介绍了贫血模型、Rich Domain Object模型、以及几种简化的模型,并分别分析了几种模型各自的优缺点。

分享到:
评论

相关推荐

    SSH架构的通用在线考试系统

    《SSH架构下的通用在线考试系统详解》 SSH(Struts + Spring + Hibernate)是一种常见的Java Web应用程序开发框架,因其灵活性、高效性和可扩展性而被广泛应用于构建各种类型的Web应用,其中包括在线考试系统。本...

    SSH架构的搭建过程

    SSH架构,全称为Struts+Spring+Hibernate,是一种在Java Web开发中常见的开源框架组合,用于构建企业级应用。SSH架构的主要目标是提供一个松耦合、可重用且易于维护的开发环境。 1. **Struts框架**: Struts是MVC...

    SSH架构性能优化方案.pdf

    SSH架构,即Struts、Spring和Hibernate的组合,是Java Web开发中的常见选择。本篇文档将聚焦于SSH架构的服务器端性能优化,探讨如何通过改进Java编程习惯来提升系统性能。 首先,关于字符串操作的优化,应当避免...

    基于SSH的基础架构设计.doc

    在SSH架构中,Spring 主要负责管理Bean,包括Struts2的Action类和Hibernate的Session工厂等。它还支持事务管理,可以协调不同数据源的操作,确保数据的一致性。 **3. Hibernate** Hibernate 是一个对象关系映射...

    SOA-SSH分层架构的设计与应用word版本.pdf

    SOA(Service-Oriented Architecture,面向服务架构)是一种软件设计策略,它强调将业务功能分解为独立的服务,这些服务可以通过网络进行互操作,以创建灵活且可复用的系统。SSH则是Java开发中的一种常见分层架构,...

    ssh架构的构建

    ### SSH架构的构建知识点 #### 一、SSH框架概述 SSH是Spring、Struts和Hibernate三个开源框架的首字母缩写。这三个框架分别是Java企业级应用开发中的三个关键部分:业务逻辑层处理(Spring)、MVC模式实现(Struts...

    票务系统JAVA 采用SSH架构

    **票务系统JAVA 采用SSH架构** 在信息技术领域,开发票务系统是一项常见的任务,而SSH(Struts2 + Spring + Hibernate)架构是Java Web应用中广泛使用的开发框架。SSH框架因其灵活性、可扩展性和模块化设计而备受...

    arm开发板-linux-ssh移植工具文件

    2. **选择SSH实现**:常见的SSH实现有OpenSSH,它是一个开源项目,包含客户端和服务器组件。我们需要下载适合ARM架构的OpenSSH源码,并根据开发板的具体版本进行配置。 3. **配置编译**:使用`./configure`脚本来...

    log4j在ssh架构下的配置使用.docx

    **三、SSH架构下使用Log4j的原因** SSH(Struts + Spring + Hibernate)是Java Web开发中常见的三层架构,其中Struts负责表现层,Spring管理业务逻辑,Hibernate处理数据持久化。由于SSH框架涉及多个组件和层次,...

    SSH2框架搭建实例源码

    SSH2框架,全称为Spring、Struts2和Hibernate2的集成框架,是Java Web开发中的一个常见组合。这个实例源码使用的是Spring 3.2、Struts2 2.3.4和Hibernate 4.2这三个框架的较新版本,提供了一个基础的用户登录和用户...

    SSH2实现的商城系统

    综上所述,这个"SSH2实现的商城系统"涵盖了Java Web开发的多个重要方面,从框架选择、数据库设计到系统架构和安全策略,都是开发者需要深入了解和掌握的知识点。通过学习和实践这样的项目,可以提升开发者在企业级...

    SSH做的BBS

    SSH是Java Web开发中常见的三大框架,它们分别负责不同的职责: 1. **Struts2**:这是一个MVC(Model-View-Controller)框架,用于处理HTTP请求并控制应用程序的流程。Struts2提供了丰富的拦截器机制,可以方便地...

    ssh.rar_SSH管理系统_ssh 管理系统_ssh bbs_ssh论坛系统_基于ssh 的论坛

    SSH,全称是Struts 2 + Spring + Hibernate,是一种常见的Java Web开发框架组合,用于构建高效、可扩展的企业级应用程序。在这个名为"ssh.rar"的压缩包中,包含了一个基于SSH框架的论坛管理系统,旨在提供一个简洁而...

    在SSH中使用事物包括SSH的搭建和配置;事物的配置;注释详细

    2. **Spring**:是整个SSH架构的核心,提供IoC(Inversion of Control)和AOP(Aspect-Oriented Programming)功能,包括事务管理。Spring通过编程式和声明式两种方式来管理事务。 3. **Hibernate**:是一个ORM...

    微博系统毕业设计论文及源代码(SSH)

    【标题】“微博系统毕业设计论文及源代码(SSH)”是一个...同时,也能掌握Web开发中的常见问题和解决策略,如权限管理、数据缓存、异常处理等。此外,论文部分可以帮助理解项目设计背后的思考,提升系统分析和设计能力。

    java程序员ssh面试常见题

    ### Java程序员SSH面试常见题详解 #### 1. Action是什么?如何证明Action是线程安全的? - **知识点概述**:在Struts框架中,Action是处理用户请求的核心组件之一,它负责执行业务逻辑并返回相应的结果。由于...

    SSH当当网项目源代码

    "SSH当当网项目源代码"是一个典型的Java Web开发项目,使用了Struts2、Spring和Hibernate这三大流行框架的组合,...通过深入研究这个项目,可以提升对SSH框架的掌握,同时也能了解实际项目开发中的常见问题和解决策略。

    全注解ssh开发

    在IT行业中,SSH(Struts2 + Spring + Hibernate)是一个非常常见的Java Web开发框架组合,用于构建高效...通过对`sample.sql`和`articleDly`的使用,可以看出开发者关注数据库设计和可能的优化策略,如数据加载策略。

    easyui整合ssh项目

    SSH框架则是Java企业级开发中常见的三层架构解决方案,用于处理业务逻辑、数据持久化以及页面展示。 【描述】提到的"孙宇老师的easyui项目"是许多开发者入门和进阶的重要资源。EasyUI以其简洁的API和直观的使用方式...

Global site tag (gtag.js) - Google Analytics