常见SSH的架构设计策略二.docx

上传人:b****8 文档编号:12396931 上传时间:2023-06-05 格式:DOCX 页数:15 大小:50.32KB
下载 相关 举报
常见SSH的架构设计策略二.docx_第1页
第1页 / 共15页
常见SSH的架构设计策略二.docx_第2页
第2页 / 共15页
常见SSH的架构设计策略二.docx_第3页
第3页 / 共15页
常见SSH的架构设计策略二.docx_第4页
第4页 / 共15页
常见SSH的架构设计策略二.docx_第5页
第5页 / 共15页
常见SSH的架构设计策略二.docx_第6页
第6页 / 共15页
常见SSH的架构设计策略二.docx_第7页
第7页 / 共15页
常见SSH的架构设计策略二.docx_第8页
第8页 / 共15页
常见SSH的架构设计策略二.docx_第9页
第9页 / 共15页
常见SSH的架构设计策略二.docx_第10页
第10页 / 共15页
常见SSH的架构设计策略二.docx_第11页
第11页 / 共15页
常见SSH的架构设计策略二.docx_第12页
第12页 / 共15页
常见SSH的架构设计策略二.docx_第13页
第13页 / 共15页
常见SSH的架构设计策略二.docx_第14页
第14页 / 共15页
常见SSH的架构设计策略二.docx_第15页
第15页 / 共15页
亲,该文档总共15页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

常见SSH的架构设计策略二.docx

《常见SSH的架构设计策略二.docx》由会员分享,可在线阅读,更多相关《常见SSH的架构设计策略二.docx(15页珍藏版)》请在冰点文库上搜索。

常见SSH的架构设计策略二.docx

常见SSH的架构设计策略二

常见SSH的架构设计策略

(二)

RichDomainObject模式

在这种模式下,DomainObject不再是单纯的数据载体,DomainObject包含了相关的业务逻辑方法。

例如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.  

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

注意:

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

在上面的业务逻辑方法中,并没有进行持久化。

如果抛开DAO层,这种DomainObject也可以独立测试,只是没有进行持久化。

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

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

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.  

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

在这里存在一个问题:

业务逻辑方法很多,哪些业务逻辑方法应该放在DomainObject对象中实现,而哪些业务逻辑方法完全由业务逻辑对象实现呢?

RodJohnson认为,可重用度高,与DomainObject密切相关的业务方法应放在DomainObject对象中实现。

业务逻辑方法是否需要由DomainObject实现的标准,从一定程序上说明了采用RichDomainObject模型的原因。

由于某些业务方法只是专一地属于某个DomainObject,因此将这些方法由DomainObject实现,能提供更好的软件复用,能更好地体现面向对象的封装性。

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

图8.2 RichDomainObject的组件关系图

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

业务逻辑对象封装DAO方法主要基于如下考虑:

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

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

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

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

—合并业务逻辑对象和DomainObject。

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

在这种模型下DAO对象不仅包含了各种CRUD方法,而且还包含各种业务逻辑方法。

此时的DAO对象,已经完成了业务逻辑对象所有任务,变成了DAO对象和业务逻辑对象混合体。

此时,业务逻辑对象依赖DomainObject,既提供基本的CRUD方法,也提供相应的业务逻辑方法。

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

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.合并业务逻辑对象和DomainObject

在这种模型下,所有的业务逻辑都应该被放在DomainObject里面,而此时的业务逻辑层不再是传统的业务逻辑层,它仅仅封装了事务和少量逻辑,完全无需DAO对象的支持。

而DomainObject依赖于DAO对象执行持久化操作,此处DomainObject和DAO对象形成双向依赖,这种设计在某些地方也被称为充血模式,但有时会带来相当大的危险。

在这种设计模式下,几乎不再需要业务逻辑层,而DomainObject则依赖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.  

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

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

这种模型的优点是:

业务逻辑对象非常简单,只提供简单的事务操作,业务逻辑对象无须依赖于DAO对象。

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

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

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

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

图8.4 合并业务逻辑组件和DoaminObject

8.4.3 抛弃业务逻辑层

在RichDomainObject模型的各种变化中,虽然努力简化业务逻辑对象,但业务逻辑对象依然存在,依然使用业务逻辑对象正面封装所有的业务请求。

下面介绍更彻底的简化即,彻底放弃业务逻辑层。

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

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

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

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

这种设计模式是充血模式更加激进的演化。

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

这种模型更加简化,使DomainObject与DAO对象形成双向依赖,而Web层的控制器直接调用DomainObject的业务逻辑方法。

这种模型在有些地方也被称为胀血模式。

这种模型的优点是:

分层少,代码实现简单。

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

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

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

这种模型与充血模式的缺点相同:

DomainObject必须配置在Spring容器中,接受Spring容器的依赖注入。

在这种架构模型下,DomainObject相当不稳定。

如果业务逻辑需要改变,DomainObject也需要发生改变,而DAO对象与DomainObject形成双向依赖,这将导致从底层的DomainObject和DAO对象的修改,使这种架构模式的分层完全失去意义。

各层之间以强耦合方式组合在一起,各层对象互相依赖,牵一发而动全身,几乎是最差的一种策略。

2.控制器完成业务逻辑

在这种模型里,控制器直接调用DAO对象的CRUD方法,通过调用基本的CRUD方法,完成对应的业务逻辑方法。

这种模型下,业务逻辑对象的功能由控制器完成。

事务则推迟到控制器中完成,因此对控制器的execute方法增加事务控制即可。

对于基本的CRUD操作,控制器可直接调用DAO对象的方法,省略了业务逻辑对象的封装,这就是这种模型的最大优势。

对于业务逻辑简单(当业务逻辑只是大量的CRUD操作时)的项目,使用这种模型也未尝不是一种好的选择。

但这种模型将导致控制变得臃肿,因为每个控制器除了包含原有的execute方法之外,还必须包含所需要的业务逻辑方法的实现。

极大地省略了业务逻辑层的开发,避免了业务逻辑对象不得不大量封装基本的CRUD方法的弊端。

这种模型也有其缺点:

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

— Web层的功能不再清晰,人为复杂化。

Web层不仅负责实现控制器逻辑,还需要完成业务逻辑的实现,因此必须精确控制何时调用DAO方法控制持久化。

—扩大了事务的影响范围。

大部分情况下,只有业务逻辑方法需要增加事务控制,而execute方法无须增加事务控制。

但如果execute方法直接调用了DAO对象的CRUD方法,则会导致这些方法不在事务环境下执行。

为了让数据库访问都在事务环境下进行,因此不得不将事务范围扩大到整个execute方法。

本章小结

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

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

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

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 高等教育 > 管理学

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2