该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2005-03-25
引用 我将这类问题,称为“大数据量操作”问题,这个名字不是很恰当,希望能有人给出更好的表达方式。
这类问题的特点是,单个 Domain Model 内的 Domain Logic ,实际上是依赖 整个 Domain Model 集合的。 就上面Item的例子来讲,Item是否符合自身的校验规则,是需要依赖所有的 Item 的。即当判断这个 Item 是否合法时,我们需要查找所有的 Item 来进行相关的校验。 这类问题,应该是 Domain Logic 的一部分。放在 Manager 之内,似乎并不适合。 你提到的这种所谓的“大数据量”操作并不是domain logic,真正的domain logic只和这个对象本身的状态有关,而这种大数据量操作是和一批domain object有关的,因此不应该放在domain object里面。 因为你一旦把这种需要一批domain ojbect的状态才能决定的大数据量操作放在domain object里面,那么你的domain object就没有办法脱离Hibernate框架,没有办法进行单元测试。 经过上面的讨论,如何区分domain logic和business logic,我想提出一个改进的区分原则: domain logic只应该和这一个domain object的实例状态有关,而不应该和一批domain object的状态有关; 当你把一个logic放到domain object中以后,这个domain object应该仍然独立于持久层框架之外(Hibernate,JDO),这个domain object仍然可以脱离持久层框架进行单元测试,这个domain object仍然是一个完备的,自包含的,不依赖于外部环境的领域对象,这种情况下,这个logic才是domain logic。 |
|
返回顶楼 | |
发表时间:2005-03-25
引用 业务实体对象属于DomainObject的一种可以同DAO接口相关。
业务控制对象也是DomainObject的一种可以同DAO接口相关。 但是我这里持久化概念可能和你理解的不一样。 持久化分为两种变更数据的,查询数据的。 变更数据的通过UnitOfWork接口实现,查询数据的通过不同的XXXXFinderDAO接口实现。 没有必要限制DomainObject对DAO接口的依赖关系,因为DomainObject在 概念上本来就有持久化的状态。去看看DDD里面关于Life Cycle Of Domain Object 的论述,里面讲到了DomainObject的状态变化,你的疑惑就该没有了。 引用 经过上面的讨论,如何区分domain logic和business logic,我想提出一个改进的区分原则:
domain logic只应该和这一个domain object的实例状态有关,而不应该和一批domain object的状态有关; 当你把一个logic放到domain object中以后,这个domain object应该仍然独立于持久层框架之外(Hibernate,JDO),这个domain object仍然可以脱离持久层框架进行单元测试,这个domain object仍然是一个完备的,自包含的,不依赖于外部环境的领域对象,这种情况下,这个logic才是domain logic。 robbin 和 partech 的观点似乎有些不同。 robbin 的观点,明确的提出了 domain logic 和 business logic 这两个概念。 partech 的观点,我从上面的文字来看,并没有区分 domain logic 和 business logic 这两种。而认为都是一种。 对我上面提到的“大数据量问题”的解决方式。 robbin 由于区分了 domain logic , business logic 所以在技术层面上,非常清晰。 partech 认为 domain object 可以依赖 XXXFinderDAO, 因此很自然的,我的大数据量问题也就不存在了。 这两种方式,我都实践过,但感觉都有明显的优缺点。 在概念上, partech 的方式,我是非常认同的,partech 提出了 实体控制对象 和 实体对象 两种不同层次的 Domain Object ,由于 Domain Object 可以依赖于 XXXFinderDAO,因此,也就不存在“大数据量问题”,因此,整个 Domain 体系,对于实际业务表述的更为完整,更为一体化。我非常倾向这种方式。但在实践中,用这种方式,我却遇到了很多的问题。无法独立测试,是最关键的一个问题。这也是robbin提到过的。 robbin的方式,更为实际,因为明显的层面切分,使得 domain 与 business 这两层非常的清晰,domain object 可以独立测试,但同样的问题 busness logic 如何测试?对于将 business logic 与 domain logic 的区分,我非常的疑惑,因为在实际业务中,象 business logic 这样的逻辑非常多,在 父子 或者 父子子 这样结构的业务单据中,更是普遍存在。而这些概念在业务上,是更偏近 domain logic 的,这样的拆分,让我觉得将一件事情拆成了两份。而大量的 business logic ,也使得装载它的 manager ,更接近于 partech 的 实体控制对象的概念。 继续小板凳,等待解惑中。。。 。。。 |
|
返回顶楼 | |
发表时间:2005-03-25
咱们论坛里大多数的DEMO之类的都是贫血的数据类。
|
|
返回顶楼 | |
发表时间:2005-03-25
七彩狼 写道 在概念上, partech 的方式,我是非常认同的,partech 提出了 实体控制对象 和 实体对象 两种不同层次的 Domain Object ,由于 Domain Object 可以依赖于 XXXFinderDAO,因此,也就不存在“大数据量问题”,因此,整个 Domain 体系,对于实际业务表述的更为完整,更为一体化。我非常倾向这种方式。但在实践中,用这种方式,我却遇到了很多的问题。无法独立测试,是最关键的一个问题。这也是robbin提到过的。
怎么会无法测试呢?DAO都是接口,做一个实现该接口的实现直接返回需要的对象。很困难吗? |
|
返回顶楼 | |
发表时间:2005-03-25
robbin 写道 应该说partech的观点是最符合Martin Fowler在POEAA中描述的模型的,但是我并不完全同意Martin Fowler的模型,我认为这种模型过于理想化,在实际项目中,会显得很罗嗦冗余,例如使用UnitOfWork来改变对象状态,使用QueryObject处理查询,又有Servier,Manager,Mapper等等等等
是啊,我承认如果你只是开发象论坛这样的程序,那么这种设计确实是复杂了些。推荐使用TableModule的模式。 使用DomainModel模式,主要是为了处理复杂的应用准备的。 看看这张POEAA的图就很清楚,当业务逻辑不复杂时, TableModule模式的业务层占很大的优势,随着业务逻辑的复杂,DomainModel才开始取得优势。可以看出DomainModel基本上是一条平滑的直线。而TransactionScript和TableModule都是一条类似于N次方程式的曲线。 这说明DomainModel很好的吻合问题域,这种复杂是本质性的复杂,问题在于需要解决的问题本身就有这么复杂。 而其它两者,除了本质性的复杂外,还有自身造成的非本质性复杂,导致了难度在复杂业务逻辑的情况下,增长很快。 |
|
返回顶楼 | |
发表时间:2005-03-25
引用 怎么会无法测试呢?DAO都是接口,做一个实现该接口的实现直接返回需要的对象。很困难吗?
呵呵,刚才写这句话的时候,我就已经意识到我的话说的有问题了。我的本意其实是,并不是DAO无法测试,而是无法测试 DAO 的查询逻辑。 该怎么说,才能清楚些呢? 这样吧,举个例子: 在我的实践中,对于查询类的DAO接口,并没有采用无限扩大的方法,也就是说,有一个逻辑查询,就要实现一个DAO的接口方法。 我是写了一些统一的查询接口,类似: interface dao { object query(class clazz, Criteria criteria); } 这里的 Criteria ,并不是Hibernate中的Criteria ,是独立存在的。 Criteria做为一种业务规则,也是属于Domain层的。但并不一定在 Domain Object 之中。 本来是想在别的帖子里,表达此观点的,也就不扩展了。 我所谓的DAO无法测试,是想指对于 Criteria 的逻辑无法测试。 在Hibernate,JDBC中,我们都会碰到这样的问题,大段的SQL或HQL,其实表示的也是一种业务逻辑,但我们却没有办法测试。只能通过数据库。 这个主题,已经偏离了这篇帖子,因此也就就此打住吧,或者另外开贴。 |
|
返回顶楼 | |
发表时间:2005-03-25
(没有深刻理解Domain Model)删除原先的观点
|
|
返回顶楼 | |
发表时间:2005-03-25
七彩狼 写道 呵呵,刚才写这句话的时候,我就已经意识到我的话说的有问题了。我的本意其实是,并不是DAO无法测试,而是无法测试 DAO 的查询逻辑。 该怎么说,才能清楚些呢? 这样吧,举个例子: 在我的实践中,对于查询类的DAO接口,并没有采用无限扩大的方法,也就是说,有一个逻辑查询,就要实现一个DAO的接口方法。 我是写了一些统一的查询接口,类似: interface dao { object query(class clazz, Criteria criteria); } 这里的 Criteria ,并不是Hibernate中的Criteria ,是独立存在的。 Criteria做为一种业务规则,也是属于Domain层的。但并不一定在 Domain Object 之中。 本来是想在别的帖子里,表达此观点的,也就不扩展了。 我所谓的DAO无法测试,是想指对于 Criteria 的逻辑无法测试。 在Hibernate,JDBC中,我们都会碰到这样的问题,大段的SQL或HQL,其实表示的也是一种业务逻辑,但我们却没有办法测试。只能通过数据库。 为什么要采用统一的查询模式呢? 越通用的接口就越缺乏约束性,而且因为使用的地方太多,就不得不考虑到很多的情况。 public interface ICustomerFinder { Customer findByID(Long id);; Customer findByCode(String code);; DomainObjectCollection findByName(String name);; } 这样的接口很清晰,不是吗? Criteria的条件,我认为最好不要作为DAO接口的参数,正如你说的太复杂了不好测试。 DAOImplement不是依赖DomainObject吗?那它就可以知道DomainObject的关系,传递的查询条件的参数只需要是很简单的类型就是了。 不知道有没有解决你的疑惑? |
|
返回顶楼 | |
发表时间:2005-03-25
引用 其实我在前面已经强调过一次,在这里再强调一次。 为什么O/R Mapping流行之前,我们无法使用Rich domain object的模型?就是因为技术限制。我在02年的时候已经采用Rich domain object做了一个小项目,但是做到后来不得不全部改成贫血的domain object?你说你设计软件架构的时候能够完全抛开技术限制,天马行空的随便搞吗?不可能的 这个我很赞同.我想在我对现在技术发展的理解(可能我的知识面有限,希望大家不要笑话我),在我的认知范围内提出些看法: 首先ORM框架的发展,已经可以支撑起了Rich domain object的模型。这一点大家已经取得一致了,那么是否ORM框架的功能是标准化了呢?是否我们用hibernate框架作的系统,可以轻易的移植到JDO上呢,我记得在hibernate in action上看到好像大案是否定的(可能是我主观臆断,以我的知识面来说是很难的)。 所以对于 引用 当你把一个logic放到domain object中以后,这个domain object应该仍然独立于持久层框架之外(Hibernate,JDO),这个domain object仍然可以脱离持久层框架进行单元测试,这个domain object仍然是一个完备的,自包含的,不依赖于外部环境的领域对象,这种情况下,这个logic才是domain logic。 仅仅mock一个作为测试还是可以的,但真的要换掉还是有难度的。 关于事务 引用 我的本意就是第二种模型,事务万万不能放在Item里边管理啊!Archie 我很同意,我以前做过com,发现里面有事务的配置,就发觉很方便,但是配置很麻烦,ejb也同样,我们上一个项目ibm向我们推销websphere的同时还劝我们不要用ejb说性能很差可见一斑,但是当初作项目的时候就发现管理事务边界(就像prech说到的service)的类事在是一件很繁琐的事情 :特别是在字典表维护上:UPDATE DELETE READ INSERT 四种 每种都可能和read 组成事务,每个事务一个类,后者复写template中的方法,其实很多业务就是在不断的组合。但是现在有了aop的方法,关于事务可以交给spring这样的容器管理,或者采用openInView模式(事务的粒度变大)基本可以解决了,所以不是对事务要求特别高的系统,Domain Object建立和事务之间的关系就不会很大。 关于DAO 发现这个贴子对了dao 和 domain objec的双向依赖问题讨论的很多,我想谈谈我的想法。其实dao从事的就是 UPDATE DELETE READ INSERT 操作,先撇开read 。UPDATE DELETE INSERT 这三个方法其实 ORM 框架都提供了很好的解决方案。就拿hibernate 的 Session来说(其他框架也提供了相似的概念) session.update(); session.delete,session.insert()其实不必每个类如item topic等都要一个ado只要建立一个 DAO ,把三个方法代理一下就行了(如果能换框架的话 换一组代理),负责的在于read,业务的不同read语义实在太丰富了,想必大家都有同感!其实但是不同的框架有不同的查询语言真的要替换也和重写差不多了。其实把它看作domain object的工厂也可,他们之间相互依赖也很正常。 置于他的位置,我认为简单的如ByID这种直接放在domain object里面有何不可,就作为构造函数之一了。复杂的还是拿到外面去(其实复杂的和bussiness flow应该很相关的)。 所以我的结论是DAO大可只有一个就是SESSION的包装。要测试直接mock SESSION。 所以我的模型是 一般情况下就不要bussiness flow 直接在 如struts的action里面调用domain Ojbect(他自己能处理持久化)这对于60%--80%的简单的业务够用了。(比如各种表的维护 ,简单订单的填写) 还有20% 的业务 在用bussiness flow 包装 bussion object 比如财务中的月结日结。 总之action里面的代码不要太长就行。 |
|
返回顶楼 | |
发表时间:2005-03-25
Martin Fowler的POEAA是2002年出版的,写作时间估计是2001年底,那时候Hibernate刚刚诞生,JDO1.0标准都没有出来。 现在时代已经完全不同了,O/R Mapping已经如此流行,而且像Spring这种可以进行完善的数据库资源管理和容器事务控制的轻量级容器也出现了,Marin的的书中提出的概念和解决方案并不完全适用于现在的流行框架了。我到建议大家去看without EJB,更加具有实用价值。
|
|
返回顶楼 | |