老妖的博客
现实的中没有几个人能够真为对方去死,甚至山盟海誓很快就会在金钱面前变的微不足道,这才是生活。没有永远的爱,除了你的父母对你,当然也就没有永远的恨,更没有永远的痛,时间是最好的治疗大师,它会很快抚平你心灵上累累的伤痕。很多年以后你想起来时,那些在你生命中汹涌来往的人群至多是个模糊的影子或者毫无意义的名字
posts - 105,  comments - 171,  trackbacks - 0
Domain Object Model and Hibernate detached object
假定我现在正在设计一套图书馆自动化系统,我想设计为领域驱动模型(也就是非贫血模型),持久层的模型为hibernate O/R Mapping
http://www.martinfowler.com/bliki/AnemicDomainModel.html
让我们来关注系统中的三个类文件:LibraryUser , Borrow and Item
表关系如下:
LibraryUser --(1:M)--> Borrow <--(1:1)--> Item [<--(M:1)-- Book]
LibraryUser.java:
 1 public class LibraryUser implements java.io.Serializable {
 2 
 3     private Long id;
 4     private Long version;
 5     private String cardKey;
 6     private String unifiedKey;
 7     private Date admissionDate;
 8     private Date expiryDate;
 9     private Set borrows = new HashSet();
10     private Set reservations = new HashSet();
11     private Set libraryUserTypes = new HashSet();
12         ..
13 
14     // get , set
15 
16 }
17 Borrow.java:
18 public class Borrow  implements java.io.Serializable {
19 
20     private Long id;
21          private Long version;
22          private Date borrowDate;
23          private Date dueDate;
24          private Date returnDate;
25          private Date reportlostDate;
26          private Short renewedNo;
27          private LibraryUserType libraryUserType;
28          private Item item;
29          private LibraryUser libraryUser;
30     ..
31 
32     // get,set
33 
34 }
35 Item.java:
36 public class Item  implements java.io.Serializable {
37 
38          private Long id;
39          private Long version;
40          private String barcode;
41          private String shelfMark;
42          private Date lastCheckin;
43          private Set borrows = new HashSet();
44          private Book book;
45          private ItemDuration itemDuration;
46          private ItemStatus itemStatus;
47          private ItemType itemType;
48          private Location location;
49          ..
50 
51     // get,set
52 
53 }

在三个类中现在仅有数据属性,现在我想再加一些方法。因为是一个图书管理系统,借书是一个常规动作,
所以第一步我想在LibraryUser类中加入borrow方法。如果我想领域驱动来设计的话应该如何放置borrow方法呢?
如果上述是正确的话,方法如下:
方法一.
LibraryUser.java,
 1 public class LibraryUser implements java.io.Serializable {
 2 
 3     ..
 4 
 5     public void borrow(Item item,LibraryUserType libraryUserType) {
 6 
 7         Borrow borrow = new Borrow();
 8         borrow.setLibraryUser(this);
 9         borrow.setLibraryUserType(libraryUserType);
10         borrow.setItem(item);
11         borrow.setBorrowDate(new Date());
12         
13         // The code here suppose to check the this libraryUser can borrow the item or not
14         // l skip it for simple dicussion , let's assume that not checking is required. :)
15          
16 
17         this.getBorrows().add(borrow);
18     }
19 
20 }
然后在我的controller中,我只是在borrow方法中传入item,libraryUserType参数保存它
controllerA
1 libraryUser.borrow(item,libraryUserType);
2 getLibrary().storeLibraryUser(libraryUser);
这样看起来较为常见,因为每一个libraryUser借书,所以borrow方法应当属于libraryUser
但是如果我们要级联保存liberaryUser(libraryUser是独立的)的话,会导致会导致多次更新借书,除非你
在borrow.hbm.xml设置select-before-update="true",但是会导致一些性能损失。
Of course , we can do it another way , feed libraryUser, item , libraryUserType into borrow , and save borrow ,
当然我们可以将libraryUser, item , libraryUserType注入borrow中来达到同样的效果
方法二、
1     Borrow borrow = new Borrow();
2     borrow.setLibraryUser(libraryUser);
3     borrow.setLibraryUserType(libraryUserType);
4     borrow.setItem(item);
5     borrow.setBorrowDate(new Date());
6     
7 
8     getLibrary().storeBorrow(borrow);
这个方法对于关系型数据库来说是非常常见的一种方法,保存一个borrow对象,
我们仅仅需要LIBRARY_USER_ID, ITEM_ID ,LIBRARY_USER_TYPE_ID , 当然还有DUE_DATE , ...等等
他只执行一句query.
insert into BORROWS (VERSION, BORROW_DATE, DUE_DATE, RETURN_DATE, REPORTLOST_DATE, RENEWED_NO, LIBRARY_USER_TYPE_ID, ITEM_ID, USER_IDvalues (?, ?, ?, ?, ?, ?, ?, ?, ?)

Q1. 方法2是否是一个贫血的领域模型呢?
Q2. 领域建摩的方法是什么,我是不是从一开始就错了呢?

------------------reply----------------------
It wasnt clear from that what the relationship is between a borrow and a book.
从上述描述来看在borrow和book之间的关系不是很清晰。
第一个想法---封装
First thought - encapsulation...
protected的item中除了简单的属性之外有没有基于collection之类的get/set方法呢?
譬如,一个getBorrows()方法返回一个set类型,或者返回一个Collections.unmodifiableSet(borrows)
这样的话,在没有你的允许之下调用代码不能修改你的对象内部状态.
borrow方法的安置...
看起来将borrow方法放于LibraryUser中并不是最佳的位置。
你的领域内有一个书库的概念吗?很明显你想知道一个User借什么书,但是我想你更想知道所有User在同时借阅books的数量。
在这种前提下我建议你创建一个BookRepository或者其他你想要的名称。这个BookRepository总是在记录borrow和你想要得到的用户信息.
如果你让repository来控制borrow,并不级联User的borrows,那么你就可以避免上述讨论的性能损失。
一个user的borrows将会被你在内存中/inverse mapping(如果你使用hibernate的话)管理。

你阅读过<<Patterns of Enterprise Application Architecture>>或者<<Domain Driven Design>>吗?你一定会喜欢的

posted on 2005-11-03 10:50 老妖 阅读(1022) 评论(1)  编辑  收藏

FeedBack:
# re: 关于spring forum 的domain object 的第二篇讨论
2005-11-03 14:31 | Programmer's Life
Q1:以Martin Fowler对于贫血模型的定义来讲,方法二确实是贫血模型,因为分离了数据和行为。
Q2:领域建模我个人这么理解,领域建模是根据业务场景(用例或用户故事)进行OOAD形成的业务模型体,这是系统的核心模型,基于此模型再结合架构来完成整个系统的设计,想想OOAD产生的业务模型体会是怎么样的,那其实就是一个符合Martin Fowler所说的Rich Domain Model,不用为了概念而概念,其实Rich Domain Model一直存在,而且很早以前N多的系统本来就是Domain Model驱动的。

不一定任何时候Rich Domain Model就是最好的,在小的系统中Transaction Script就是比它好用,不要什么都去追求一步登天,Rich Domain Model和Anemic Domain Model各有优缺点和适合的场合。  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航:
 

<2005年11月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

常用链接

随笔分类(48)

随笔档案(104)

好友链接

我的豆瓣

积分与排名

  • 积分 - 219756
  • 排名 - 257

最新评论

阅读排行榜