- 浏览: 28813 次
- 性别:
- 来自: 福州
(转载自)轻量级J2EE企业应用实战——Struts+Spring+Hibernate整合开发 李刚
常见的架构设计策略
目前流行的轻量级J2EE应用的架构比较一致,采用的技术也比较一致,通常使用Spring作为核心,向上整合MVC框架,向下整合ORM框架。使用Spring的IOC容器来管理各组件之间的依赖关系时,Spring的声明事务将负责业务逻辑层对象方法的事务管理。
但在固定的技术组合上,依然可能存在小的变化。下面依次讨论可能存在的架构策略。
8.4.1 贫血模式
贫血模式是最常用的设计架构,也是最容易理解的架构。为了让读者通过本书顺利进入轻量级J2EE企业应用开发,本书的第9章及第10章的范例都将采用这种简单的架构模式。
所谓贫血,指Domain Object只是单纯的数据类,不包含业务逻辑方法,即每个Domain Object类只包含基本的setter和getter方法。所有的业务逻辑都由业务逻辑组件实现,这种Domain Object就是所谓的贫血的Domain Object,采用这种Domain Object的架构即所谓的贫血模式。
下面以第9章的消息发布系统的部分代码为例,介绍贫血模式。
在贫血模式里,所有的Domain Object只是单纯的数据类,只包含每个属性的setter和getter方法,如下是两个持久化类。
第一个Domain Object是消息,其代码如下:
- public class News extends BaseObject implements Serializable
- {
- //主键
- private Long id;
- //消息标题
- private String title;
- //消息内容
- private String content;
- //消息的发布时间
- private Date postDate;
- //消息的最后修改时间
- private Date lastModifyDate;
- //消息所属分类
- private Category category;
- //消息对应的消息回复
- private Set newsReviews;
- //无参数的构造器
- public News() {
- }
- //消息回复对应的getter方法
- public Set getNewsReviews() {
- return newsReviews;
- }
- //消息回复对应的setter方法
- public void setNewsReviews(Set newsReviews) {
- this.newsReviews = newsReviews;
- }
- //消息分类对应的getter方法
- public Category getCategory() {
- return category;
- }
- //消息分类对应的setter方法
- public void setCategory(Category category) {
- this.category = category;
- }
- //消息最后修改时间的getter方法
- public Date getLastModifyDate() {
- return lastModifyDate;
- }
- //消息最后修改时间的setter方法
- public void setLastModifyDate(Date lastModifyDate) {
- this.lastModifyDate = lastModifyDate;
- }
- //消息发布时间的getter方法
- public Date getPostDate() {
- return postDate;
- }
- //消息发布时间的setter方法
- public void setPostDate(Date postDate) {
- this.postDate = postDate;
- }
- //消息内容对应的getter方法
- public String getContent() {
- return content;
- }
- //消息发布者对应的setter方法
- public void setContent(String content) {
- this.content = content;
- }
- //消息主键对应的getter方法
- public Long getId() {
- return id;
- }
- //消息主键对应的setter方法
- public void setId(Long id) {
- this.id = id;
- }
- //消息标题对应的getter方法
- public String getTitle() {
- return title;
- }
- //消息标题对应的setter方法
- public void setTitle(String title) {
- this.title = title;
- }
- //Domain Object重写equals方法
- public boolean equals(Object object) {
- if (!(object instanceof News)) {
- return false;
- }
- News rhs = (News) object;
- return this.poster.equals(rhs.getPoster())
- && this.postDate.equals(rhs.getPostDate());
- }
- //Domain Object重写的hashCode方法
- public int hashCode() {
- return this.poster.hashCode() + this.postDate.hashCode();
- }
- //Domain Object重写toString方法
- public String toString() {
- return new ToStringBuilder(this).append("id", this.id).append("title",
- this.title).append("postDate", this.postDate).append("content",
- this.content).append("lastModifyDate", this.lastModifyDate)
- .append("poster", this.poster)
- .append("category", this.category).append("newsReviews",
- this.newsReviews).toString();
- }
- }
第二个Domain Object是消息对应的回复,其代码如下:
- public class NewsReview extends BaseObject
- {
- //消息回复的主键
- private Long id;
- //消息回复的内容
- private String content;
- //消息回复的回复时间
- private Date postDate;
- //回复的最后修改时间
- private Date lastModifyDate;
- //回复的对应的消息
- private News news;
- //消息回复的构造器
- public NewsReview() {
- }
- //回复内容对应的getter方法
- public String getContent() {
- return content;
- }
- //回复内容对应的setter方法
- public void setContent(String content) {
- this.content = content;
- }
- //回复主键对应的setter方法
- public Long getId() {
- return id;
- }
- //回复主键对应的setter方法
- public void setId(Long id) {
- this.id = id;
- }
- //回复的最后修改时间对应的getter方法
- public Date getLastModifyDate() {
- return lastModifyDate;
- }
- //回复的最后修改时间对应的setter方法
- public void setLastModifyDate(Date lastModifyDate) {
- this.lastModifyDate = lastModifyDate;
- }
- //回复对应的消息的getter方法
- public News getNews() {
- return news;
- }
- //回复对应的消息的setter方法
- public void setNews(News news) {
- this.news = news;
- }
- //回复发布时间的getter方法
- public Date getPostDate() {
- return postDate;
- }
- //回复发布时间的setter方法
- public void setPostDate(Date postDate) {
- this.postDate = postDate;
- }
- //Domain Object重写的equals方法
- public boolean equals(Object object) {
- if (!(object instanceof NewsReview)) {
- return false;
- }
- NewsReview rhs = (NewsReview) object;
- return this.poster.equals(rhs.getPoster()) &&
- this.postDate.equals(rhs.getPostDate());
- /*return new EqualsBuilder().append(this.news, rhs.news).append(
- this.content, rhs.content).append(this.postDate, rhs.postDate)
- .append(this.lastModifyDate, rhs.lastModifyDate).append(
- this.id, rhs.id).append(this.poster, rhs.poster)
- .isEquals();
- */
- }
- //Domain Object对应的hashCode方法
- public int hashCode() {
- return this.poster.hashCode() + this.postDate.hashCode();
- /*return new HashCodeBuilder(-1152635115, 884310249).append(this.news)
- .append(this.content).append(this.postDate).append(
- this.lastModifyDate).append(this.id)
- .append(this.poster).toHashCode();
- */
- }
- //Domain Object对应的toString方法
- public String toString() {
- return new ToStringBuilder(this).append("id", this.id).append(
- "postDate", this.postDate).append("lastModifyDate",
- this.lastModifyDate).append("content", this.content).append(
- "poster", this.poster).append("news", this.news).toString();
- }
- }
从上面贫血模式的Domain Object可看出,其类代码中只有setter和getter方法,这种Domain Object只是单纯的数据体,类似于C的数据结构。虽然它的名字是Domain Object,却没有包含任何业务对象的相关方法。Martin Fowler认为,这是一种不健康的建模方式,Domain Model既然代表了业务对象,就应该包含相关的业务方法。从语言的角度上来说,Domain Model在这里被映射为Java对象(一般都是ORM), Java对象应该是数据与动作的集合,贫血模型相当于抛弃了Java面向对象的性质。
Rod Johnson和Martin Fowler一致认为:贫血的Domain Object实际上以数据结构代替了对象。他们认为Domain Object应该是个完整的Java 对象, 既包含基本的数据,也包含了操作数据相应的业务逻辑方法。
下面是NewsDAOHibernate的源代码,该DAO对象用于操作News对象:
- //NewsDAOHibernate继承HibernateDaoSupport,实现NewsDAO接口
- public class NewsDAOHibernate extends HibernateDaoSupport implements NewsDAO
- {
- //根据主键加载消息
- public News getNews(Long id)
- {
- News news = (News) getHibernateTemplate().get(News.class, id);
- if (news == null) {
- throw new ObjectRetrievalFailureException(News.class, id);
- }
- return news;
- }
- //保存新的消息
- public void saveNews(News news) {
- getHibernateTemplate().saveOrUpdate(news);
- }
- //根据主键删除消息
- public void removeNews(Long id)
- {
- getHibernateTemplate().delete(getNews(id));
- }
- //查找全部的消息
- public List findAll()
- {
- getHibernateTemplate().find("from News"));
- }
- }
既然DAO对象完成具体的持久化操作,因此基本的CRUD操作都应该在DAO对象中实现。但DAO对象应该包含多少个查询方法,并不是确定的。因此,根据业务逻辑的不同需要, 不同的DAO对象可能有数量不等的查询方法。
对于现实中News,应该包含一个业务方法(addNewsReviews方法)。在贫血模式下,News类的代码并没有包含该业务方法,只是将该业务方法放到业务逻辑对象中实现,下面是业务逻辑对象实现addNewsReviews的代码:
- public class FacadeManagerImpl implements FacadeManager
- {
- //业务逻辑对象依赖的DAO对象
- private CategoryDAO categoryDAO;
- private NewsDAO newsDAO;
- private NewsReviewDAO newsReviewDAO;
- private UserDAO userDAO;
- //...此处还应该增加依赖注入DAO对象必需的setter方法
- //...此处还应该增加其他业务逻辑方法
- //下面是增加新闻回复的业务方法
- public NewsReview addNewsReview(Long newsId , String content)
- {
- //根据新闻id加载新闻
- News news = newsDao.getNews(newsId);
- //以默认构造器创建新闻回复
- NewsReview review = new NewsReview();
- //设置新闻与新闻回复之间的关联
- review.setNews(news);
- //设置新闻回复的内容
- review.setContent(content);
- //设置回复的回复时间
- review.setPostDate(new Date());
- //设置新闻回复的最后修改时间
- review.setLastModifyDate(new Date());
- //保存回复
- newsReviewDAO.saveNewsReview(review);
- return review;
- }
- }
在贫血模式下,业务逻辑对象正面封装了全部的业务逻辑方法,Web层仅与业务逻辑组件交互即可,无须访问底层的DAO对象。Spring的声明式事务管理将负责业务逻辑对象方法的事务性。
在贫血模式下,其分层非常清晰。Domain Object 并不具备领域对象的业务逻辑功能,仅仅是ORM框架持久化所需的POJO,仅是数据载体。贫血模型容易理解,开发便捷,但严重背离了面向对象的设计思想,所有的Domain Object并不是完整的Java对象。
总结起来,贫血模式存在如下缺点:
— 项目需要书写大量的贫血类,当然也可以借助某些工具自动生成。
— Domain Object的业务逻辑得不到体现。由于业务逻辑对象的复杂度大大增加,许多不应该由业务逻辑对象实现的业务逻辑方法,完全由业务逻辑对象实现,从而使业务逻辑对象的实现类变得相当臃肿。
贫血模式的优点是:开发简单、分层清晰、架构明晰且不易混淆;所有的依赖都是单向依赖,解耦优秀。适合于初学者及对架构把握不十分清晰的开发团队。
发表评论
-
log4j.properties
2008-01-09 19:07 0# DEBUG < INFO < WARN &l ... -
购物车总结
2007-10-21 23:03 1901购物车总结: 写一个购物车的类Cart public clas ... -
分页总结
2007-10-21 23:02 946分页总结: 通过当前页判断是否有上一页下一页和首尾页 通过总 ... -
常见SSH的架构设计策略(二)
2007-10-03 00:26 3279Rich Domain Object模式 在这种模式下,Dom ... -
java企业级应用之术语篇
2007-04-30 17:00 1212java企业级应用之术语篇 2007-04-25 来自:jav ... -
面朝大海,春暖花开
2007-04-13 21:52 28海子的<面朝大海,春暖花开> 从明天起, 做一个幸 ... -
一个做技术的女生写的散文
2007-04-13 21:39 25人们总是在不断的探求这个世界,也探求自己,总是有这种或那种让人 ...
相关推荐
《SSH架构下的通用在线考试系统详解》 SSH(Struts + Spring + Hibernate)是一种常见的Java Web应用程序开发框架,因其灵活性、高效性和可扩展性而被广泛应用于构建各种类型的Web应用,其中包括在线考试系统。本...
SSH架构,全称为Struts+Spring+Hibernate,是一种在Java Web开发中常见的开源框架组合,用于构建企业级应用。SSH架构的主要目标是提供一个松耦合、可重用且易于维护的开发环境。 1. **Struts框架**: Struts是MVC...
SSH架构,即Struts、Spring和Hibernate的组合,是Java Web开发中的常见选择。本篇文档将聚焦于SSH架构的服务器端性能优化,探讨如何通过改进Java编程习惯来提升系统性能。 首先,关于字符串操作的优化,应当避免...
在SSH架构中,Spring 主要负责管理Bean,包括Struts2的Action类和Hibernate的Session工厂等。它还支持事务管理,可以协调不同数据源的操作,确保数据的一致性。 **3. Hibernate** Hibernate 是一个对象关系映射...
SOA(Service-Oriented Architecture,面向服务架构)是一种软件设计策略,它强调将业务功能分解为独立的服务,这些服务可以通过网络进行互操作,以创建灵活且可复用的系统。SSH则是Java开发中的一种常见分层架构,...
### SSH架构的构建知识点 #### 一、SSH框架概述 SSH是Spring、Struts和Hibernate三个开源框架的首字母缩写。这三个框架分别是Java企业级应用开发中的三个关键部分:业务逻辑层处理(Spring)、MVC模式实现(Struts...
总的来说,基于SSH架构的Java票务系统是一个综合性的项目,涵盖了Web开发、数据库管理、业务逻辑处理等多个方面的知识。在实际开发过程中,还需要考虑系统的可维护性、可扩展性和性能,以满足不同规模和需求的票务...
2. **选择SSH实现**:常见的SSH实现有OpenSSH,它是一个开源项目,包含客户端和服务器组件。我们需要下载适合ARM架构的OpenSSH源码,并根据开发板的具体版本进行配置。 3. **配置编译**:使用`./configure`脚本来...
**三、SSH架构下使用Log4j的原因** SSH(Struts + Spring + Hibernate)是Java Web开发中常见的三层架构,其中Struts负责表现层,Spring管理业务逻辑,Hibernate处理数据持久化。由于SSH框架涉及多个组件和层次,...
SSH2框架,全称为Spring、Struts2和Hibernate2的集成框架,是Java Web开发中的一个常见组合。这个实例源码使用的是Spring 3.2、Struts2 2.3.4和Hibernate 4.2这三个框架的较新版本,提供了一个基础的用户登录和用户...
SSH2(Struts2 + Spring + Hibernate2)是一种常见的Java Web开发框架组合,它整合了三个强大的开源项目,用于构建高效、可维护的企业级应用程序。在这个"SSH2实现的商城系统"中,我们主要探讨以下几个核心知识点: ...
SSH,全称是Struts 2 + Spring + Hibernate,是一种常见的Java Web开发框架组合,用于构建高效、可扩展的企业级应用程序。在这个名为"ssh.rar"的压缩包中,包含了一个基于SSH框架的论坛管理系统,旨在提供一个简洁而...
SSH是Java Web开发中常见的三大框架,它们分别负责不同的职责: 1. **Struts2**:这是一个MVC(Model-View-Controller)框架,用于处理HTTP请求并控制应用程序的流程。Struts2提供了丰富的拦截器机制,可以方便地...
【描述】提到这是一个“优秀毕业设计”,意味着该设计不仅完成了基本的功能实现,还可能在用户体验、性能优化或系统架构上有出色的表现。毕业设计通常包括需求分析、系统设计、编码实现、测试以及论文撰写等多个环节...
SSH是一个常见的Java Web开发栈,用于构建高效、模块化且可维护的应用程序。下面我们将深入探讨SSH中的事务管理和配置。 首先,SSH中的每一个组件都有其在事务处理中的角色: 1. **Struts2**:作为MVC框架,主要...
"SSH当当网项目源代码"是一个典型的Java Web开发项目,使用了Struts2、Spring和Hibernate这三大流行框架的组合,...通过深入研究这个项目,可以提升对SSH框架的掌握,同时也能了解实际项目开发中的常见问题和解决策略。
### Java程序员SSH面试常见题详解 #### 1. Action是什么?如何证明Action是线程安全的? - **知识点概述**:在Struts框架中,Action是处理用户请求的核心组件之一,它负责执行业务逻辑并返回相应的结果。由于...
在IT行业中,SSH(Struts2 + Spring + Hibernate)是一个非常常见的Java Web开发框架组合,用于构建高效、可维护的企业级应用。这个“全注解SSH开发”主题着重于使用注解来简化SSH框架的配置,提高开发效率。以下是...
SSH框架,全称为Struts2、Spring和Hibernate的组合,是Java Web开发中常见的三大开源框架集成。这个框架集合提供了模型-视图-控制器(MVC)架构模式,以及依赖注入(DI)和面向切面编程(AOP)的能力,大大简化了Web...