论坛首页 Java企业应用论坛

domain model的延伸讨论

浏览 73073 次
该帖已经被评为精华帖
作者 正文
   发表时间:2007-03-03  
robbin 写道

我写这个例子不是想比较代码行数的。否则我就不会omit那么多信息了。我想说明的无非就是两点:

1、充血模型RoR实现起来很简单,而Java可以实现但有技术上的难度
2、RoR更加适合采用充血模型,而其复杂业务逻辑描述能力强于Java

只不过某些人硬是说Java也可以很方便的充血,而且RoR只能做简单web项目,硬说复杂企业业务逻辑Java描述能力更强。所以我在等这些人把代码给我贴出来,我好继续讨论下去。


Well,我也并没有在揣测你的意图。
对我来说,LOC makes sense。假如这个例子在Java中能用56行写完rich model(两倍于Ruby,够宽容了),我相信Java中没有理由不用rich model。
0 请登录后投票
   发表时间:2007-03-03  
另外注意Employee里的Password实现, 完全由这个类自己处理, 而不是提供 getter/setter 由 service 去处理.
0 请登录后投票
   发表时间:2007-03-03  
还有, employees 集合和 tasks 集合是数据库系统(TOB)维护的, 你birth一个employee或者task, 它就自动加到相应 department 对象 和 employee 对象的集合中去. 如果事务提交失败, 原来的集合内容就会自动恢复.

AR中还是需要应用自己去维护相关对象集合, 那么在事务失败的时候是否就需要应用自己修复这些集合呢?
0 请登录后投票
   发表时间:2007-03-03  
另外从Robbin的AR的代码中看不出级联删除的实现, TOB的模型中因为这个判断是应用重载 Tie.killingTargetNotify() 来实现的, 其中可以进行任意复杂的判断, 决定是删是留, 或者做其它处理. 这个地方如果不重载, 默认的处理在一个 Department 被删除后, 它所有的 Employee的 department 引用都会被清空. 删Employee时Task的处理类似.

不知道这个灵活性在AR中是怎么支持的.
0 请登录后投票
   发表时间:2007-03-03  
User与UserList是不一样的。

addUser这样的操作,就应该放在UserList里做。

把UserList要完成的工作打包在一起,命名为UserService,也是很自然的事情。因为UserList,很难被认为是一个对象实体。
0 请登录后投票
   发表时间:2007-03-03  
庄表伟 写道
User与UserList是不一样的。

addUser这样的操作,就应该放在UserList里做。

把UserList要完成的工作打包在一起,命名为UserService,也是很自然的事情。因为UserList,很难被认为是一个对象实体。


如果这个UserList是一个Department的所有成员列表, 那么这个List本身是不是可以认为是Department的一部分呢?

其实这是关系模型真正的好处, 你指定了一个 User 的 Dep 是xx, 那么那个Dep的成员列表在逻辑上就直接包含了这个User. TOB是把这种关系在系统级别自动实现了, addUser到一个Dep的memberList是直接依赖于这个User的dep属性的, 如果必须自己维护保障其一致性, 对持久应用来说应该是一种负担吧.

网络模型是从Dep用一个列表引用User, 而关系模型是设定User的Dep属性 (传统上称为Foreign Key, 而在TOB中发展成Tie引用).
0 请登录后投票
   发表时间:2007-03-03  
UserList!=Department

一个人进入公司,还没有进入部门,他就可以是一个员工了。
某某员工,加入某某部门或退出某某部门,甚至一个员工属于多个部门,都是自然的现象。
因此,Department可以维护一个“user-department”关系表。

但是,这不等于UserList
0 请登录后投票
   发表时间:2007-03-03  
:S 那就搞不清楚这个UserList是指什么了... 是说数据库中所有User?

还是说就是可以单独管理的List对象? 如果是这样那可以单独定义为一个UserList持久类, 这样Dep也许还可以从它继承呢.
0 请登录后投票
   发表时间:2007-03-03  
还是就例子本身来进行探讨吧,比较巧的是我恰巧实施过这样一个类似任务管理的项目,因此我觉得有必要把这个模型再复杂化一些.

在task(任务)上再加上kind(类别),start_time(开始时间),end_time(结束时间)
kind(类别)和user(员工)有多对多的关联关系,该关联关系可以认为是相对静态的.一个员工只能处理他相关类别的任务.

增加以下几个需求:
6.列出当前员工已经开始但尚未结束的任务
7.列出所有员工已经开始但尚未结束的任务
8.对某一类别,给所有和此一类别相关的员工,批量新增一批任务,这批任务的名称/开始时间/结束时间全部相同
9.对某一类别,统计当月总的任务数,已完成任务数,未完成任务数.对于任何一数值,均可以按员工进一步细化.


列出这些要求的目的是为了讨论我一直以来的一个想法:
OO和关系运算两者是适合不同的需求的,这两者互相都不能完全包容对方.领域建模是OO领域的概念.

OO更适用于对单个业务对象的操作
关系运算则适用于横跨多个业务对象的批量操作

robbin例子中的1/2/3是属于关系运算的范畴,只是因为相对简单,所以似乎可以用领域建模来包容,但是一旦复杂化之后难度就倍增了.
关键的问题在于:user类中的has_many:tasks和self.tasks
这是伪领域建模


ruby的一大创造就是广泛应用了复数概念,可以更自然的在OO框架下获得关系运算的好处,这一点我认为确实比java要强的多.
而在4/5这两个纯OO的需求之下,java仍然可以轻松满足(当然还有代码量的差别).







0 请登录后投票
   发表时间:2007-03-03  
嗯, 难以用 SQL 表达的复杂的统计匹配条件, AR就没法占到直接SQL的优势了, 可能写出来代码量也要增加了.
另外不知道这种情况下AR处理起并发访问来, 比如统计一个人的工作量中途时, 这个人有新增任务, 或者删除掉了一些任务, 结果会怎么样?

另关于TOB中处理复数的一点提示:

当相关对象只可能有一个时, 用一个 Kin<R,T> 类型的field来引用, 其中R是建立关联的持久关系类型, T是相关对象的类型.

当相关对象可能有多个时, 用一个 KinSet<R,T> 类型的field来引用, 其中R和T的含义相同. 同时KinSet<R,T> implements Iterable<Kin<R,T>>, 所以可以用在 for(Kin<R,T> kin : kinSet) 这样的循环中.

通过这种方式, 语义更加直白明确, 根本不需要再考虑 One-One, One-Many, Many-Many 的问题, 只要在自己这边看逻辑上相关对象是否可能有多个, 相应的定义一个field就可以了, 另一边也是独立的去看, 不用两边单复数情况先排列组合起来再分析了. 这点好像跟AR有点异曲同工.
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics