- 浏览: 28249 次
- 性别:
- 来自: 福州
(转载自)轻量级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 1871购物车总结: 写一个购物车的类Cart public clas ... -
分页总结
2007-10-21 23:02 914分页总结: 通过当前页判断是否有上一页下一页和首尾页 通过总 ... -
常见SSH的架构设计策略(二)
2007-10-03 00:26 3245Rich Domain Object模式 在这种模式下,Dom ... -
java企业级应用之术语篇
2007-04-30 17:00 1180java企业级应用之术语篇 2007-04-25 来自:jav ... -
面朝大海,春暖花开
2007-04-13 21:52 28海子的<面朝大海,春暖花开> 从明天起, 做一个幸 ... -
一个做技术的女生写的散文
2007-04-13 21:39 25人们总是在不断的探求这个世界,也探求自己,总是有这种或那种让人 ...
相关推荐
SSH架构搭建,SSH架构
UnitWorkUnitWorkUnitWUnitWorkorkUnitWork
java ssh 架构说明
基于SSH架构的J2EEOA的设计与实现是一片很好的论文
SOA-SSH分层架构的设计与应用word版本.docxSOA-SSH分层架构的设计与应用word版本.docxSOA-SSH分层架构的设计与应用word版本.docxSOA-SSH分层架构的设计与应用word版本.docxSOA-SSH分层架构的设计与应用word版本....
SOA-SSH分层架构的设计与应用word版本.pdfSOA-SSH分层架构的设计与应用word版本.pdfSOA-SSH分层架构的设计与应用word版本.pdfSOA-SSH分层架构的设计与应用word版本.pdfSOA-SSH分层架构的设计与应用word版本.pdfSOA-...
Java中搭建SSH架构的常用jar包全在里面了。2009.11.03
ssh架构实现登陆,使用Oracle数据库,仅供参考
SSH搭建
J2ee Struts,Spring Framework,Hibernate 经典结合,项目源码。控制层、数据层、业务层分层 架构经典搭配,学习、研究的好东西。
基于SSH架构的培训机构教务系统源码+项目说明.zip基于SSH架构的培训机构教务系统源码+项目说明.zip基于SSH架构的培训机构教务系统源码+项目说明.zip基于SSH架构的培训机构教务系统源码+项目说明.zip基于SSH架构的...
bbs系统,ssh架构,数据库为sqlserver 麻雀虽小五脏俱全,前台后台所有基本功能都有。
架构规范 SSH 框架 架构规范 SSH 框架
SSH(Struts2\Spring\Hibernate三大框架)的整合开发文档
1、 SSH架构总体描述。 2、 框架集成规范。 3、 组件集成规范。 4、 包结构规范。 5、 架构规约。
SSH架构的学生管理系统(附带数据库),供学习SSH的同好学习使用,保证满意
基于SSH架构的Web系统的开发方法
SSH架构测试代码,很好的测试代码,最新整理的,用于学习
ssh java 使用SSH架构实现《青鸟租房》ssh java 使用SSH架构实现《青鸟租房》
基于SSH架构的银行支付系统的设计与实现