该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2005-03-21
albert_qhd 写道 举一个简单的例子吧
比如Order类,每个Order有好些Item 按照Hibernate实体类是这样 public class Order { ... public void setItems(Collection items); { ... } public Collection getItems(); { return items; } } 这样的话,添加item的逻辑写在Order外面,Order什么都没做,只是一个数据容器,当然是“贫血”的 而用domain 方式如下: public class Order { public void addItem(Item item); { ...判断是否重复,重复则只增加数量等等逻辑 } public Collection getItems(); ... public void removeItem(Item item); ... } 这就好多了 呵呵 ,多余! 就算是贫血的模型! 这种操作也需要进行判断。 本身所维护的行为实体类还是至少需要保证的。 |
|
返回顶楼 | |
发表时间:2005-03-21
你觉得addItem方法太简单了?
那就再复杂一点,比如addItem的时候要去检查一下库存。 假设你有好几个地方都用到addItem,hibernate实体类的方式将导致大量重复的代码 |
|
返回顶楼 | |
发表时间:2005-03-21
引用 这实际上是因为术语的不同定义和理解导致的问题。
Martin Fowler提到的Domain Model并不是你这里所说的概念。 你所说的概念是RUP的概念,领域模型是作为业务建模的简化版本来定义的。 想想看,Martin Fowler是把TransactionScript,TableModule,DomainModel三者是放在并列的位置讨论的。用你的观点来解释能解释得通吗? 下面是martin Fowler认为 贫血的DomainModel的问题所在。 The fundamental horror of this anti-pattern is that it's so contrary to the basic idea of object-oriented design; which is to combine data and process together. The anemic domain model is really just a procedural style design, exactly the kind of thing that object bigots like me (and Eric) have been fighting since our early days in Smalltalk. What's worse, many people think that anemic objects are real objects, and thus completely miss the point of what object-oriented design is all about. 数据与行为分离,违反OO封装的基本原理。我想这是最明显不过了。 把我的数据和你的行为整合到一起,这就是OO封装的基本原理? 你要搞清楚什么才是一个数据类的内在行为,而不要把本来不是这个数据类的行为误以为是这个数据类的行为。 我可以给你一个准则: 实体类是有状态的类,凡是针对实体类有状态的操作,你可以考虑一下是否是该实体类的行为,而凡是无状态的操作,它基本上就不是该实体类的行为。 还是就上面举的这个例子来看,Order类的addItem方法和removeItem方法是和Order类的某个具体实例紧密绑定的,换句话说就是,这两个方法是有状态的行为,所以他们是Order类的行为,必须放在Order类里面,而其他的所谓updateOrder,saveOrder,findOrders等等统统都不是和具体Order类实例绑定的,即全部都是无状态的操作。这些无状态的操作并不是实体类的行为,他们和实体类的关系只是消息的消费者和消息之间的依赖关系,并不是类内部属性和方法之间的紧密关联关系。。 这些无状态的方法只不过接收实体类作为消息来消费他们而已。我们对比一下Struts Action的 execute(HttpServletRequest request, HttpServletResponse response, ActionFormBean formBean, ...);; Action接收request和response,请注意,Struts的action是无状态的操作,而request和response是有状态的类,在这里request,response,formBean都是消息,而Action的execute是这些消息的消费者,你不会认为应该把Action的execute方法放到request对象里面吧? 好吧,那么我们再看看实体类和实体类的DAO接口: AccountDao: updateAccount(Account account);; 比较一下,完全没有区别!这就说明updateAccount这个行为他和Account之间只存在消息的消费者和消息,而不是类方法的关系。 请记住上面这个Struts Action的例子,按照你们的逻辑,execute方法就不应该放在Action里面,而应该整合到request对象里面去。看起来很荒谬吧,其实你们的逻辑推导的结果就是这样。本质上你们又犯了偷换概念的错误,混淆了类的行为和类作为消息的外部消费者。 |
|
返回顶楼 | |
发表时间:2005-03-21
robbin 写道 我可以给你一个准则: 实体类是有状态的类,凡是针对实体类有状态的操作,你可以考虑一下是否是该实体类的行为,而凡是无状态的操作,它基本上就不是该实体类的行为。 还是就上面举的这个例子来看,Order类的addItem方法和removeItem方法是和Order类的某个具体实例紧密绑定的,换句话说就是,这两个方法是有状态的行为,所以他们是Order类的行为,必须放在Order类里面,而其他的所谓updateOrder,saveOrder,findOrders等等统统都不是和具体Order类实例绑定的,即全部都是无状态的操作。这些无状态的操作并不是实体类的行为,他们和实体类的关系只是消息的消费者和消息之间的依赖关系,并不是类内部属性和方法之间的紧密关联关系。。 唔,应该是把持久化的操作分离出来。 |
|
返回顶楼 | |
发表时间:2005-03-21
robbin 写道 还是就上面举的这个例子来看,Order类的addItem方法和removeItem方法是和Order类的某个具体实例紧密绑定的,换句话说就是,这两个方法是有状态的行为,所以他们是Order类的行为,必须放在Order类里面,而其他的所谓updateOrder,saveOrder,findOrders等等统统都不是和具体Order类实例绑定的,即全部都是无状态的操作。这些无状态的操作并不是实体类的行为,他们和实体类的关系只是消息的消费者和消息之间的依赖关系,并不是类内部属性和方法之间的紧密关联关系。。
哦,那对于什么样的Item可以加入什么样的Order这样的业务逻辑,是不是也要和人员加入角色一样的处理,把业务逻辑放到OrderManager中呢? |
|
返回顶楼 | |
发表时间:2005-03-22
robbin 写道 我可以给你一个准则: 实体类是有状态的类,凡是针对实体类有状态的操作,你可以考虑一下是否是该实体类的行为,而凡是无状态的操作,它基本上就不是该实体类的行为。 首先,我还是建议你去研究一下RUP同MartinFowler关于DomainModel的不同定义。否则大家讨论就是鸡同鸭讲了。 你说的这个原则我可以不可以这样理解? 有状态的操作,指改变实体属性的操作。 无状态操作,不改变实体属性的操作。 robbin 写道 还是就上面举的这个例子来看,Order类的addItem方法和removeItem方法是和Order类的某个具体实例紧密绑定的,换句话说就是,这两个方法是有状态的行为,所以他们是Order类的行为,必须放在Order类里面,而其他的所谓updateOrder,saveOrder,findOrders等等统统都不是和具体Order类实例绑定的,即全部都是无状态的操作。这些无状态的操作并不是实体类的行为,他们和实体类的关系只是消息的消费者和消息之间的依赖关系,并不是类内部属性和方法之间的紧密关联关系。。 好吧,那么我们再看看实体类和实体类的DAO接口: AccountDao: updateAccount(Account account);; 比较一下,完全没有区别!这就说明updateAccount这个行为他和Account之间只存在消息的消费者和消息,而不是类方法的关系。 请记住上面这个Struts Action的例子,按照你们的逻辑,execute方法就不应该放在Action里面,而应该整合到request对象里面去。看起来很荒谬吧,其实你们的逻辑推导的结果就是这样。本质上你们又犯了偷换概念的错误,混淆了类的行为和类作为消息的外部消费者。 没错,你的这种观点是对的。持久化的方法是不能放入DomainObject中。 看看MartinFowler的大作11章的UnitOfWork和18章的Separated Interface。DomainObject实际上只需要知道UnitOfWork的接口。 |
|
返回顶楼 | |
发表时间:2005-03-23
引用 还是就上面举的这个例子来看,Order类的addItem方法和removeItem方法是和Order类的某个具体实例紧密绑定的,换句话说就是,这两个方法是有状态的行为,所以他们是Order类的行为,必须放在Order类里面,而其他的所谓updateOrder,saveOrder,findOrders等等统统都不是和具体Order类实例绑定的,即全部都是无状态的操作。这些无状态的操作并不是实体类的行为,他们和实体类的关系只是消息的消费者和消息之间的依赖关系,并不是类内部属性和方法之间的紧密关联关系。。 updateOrder,saveOrder 为什么是无状态的?,恰恰相反,对于order而言,这两个防范恰恰是对order状态的确认.先看一下为什么要updateOrder? 是为了放入数据库么?不是?只是做一种确认,确认我order在n天后没有被别人edit过的话,他还是现在我确认的状态.所以完全可以做order.update(); order.save();都是对自身状态的刷新,从不稳定状态到稳定状态。 再来看看orm框架的目标是什么,就是为了让它的client看到的是对象。我拿到了order 我就可以order.getItem();这不就是hibernate 等orm框架 所努力的方向么而不是orderADO.getitem(connection,order,getID());当开始从数据库拿到order时候:order的状态是持久的,order.setProperty();后它的状态有可能 是dirty的,通过噢仁的人。update();确保他的状态在that moment是一致的,恰恰是数据不同状态的切换阿 |
|
返回顶楼 | |
发表时间:2005-03-23
frankensteinlin 写道 引用 还是就上面举的这个例子来看,Order类的addItem方法和removeItem方法是和Order类的某个具体实例紧密绑定的,换句话说就是,这两个方法是有状态的行为,所以他们是Order类的行为,必须放在Order类里面,而其他的所谓updateOrder,saveOrder,findOrders等等统统都不是和具体Order类实例绑定的,即全部都是无状态的操作。这些无状态的操作并不是实体类的行为,他们和实体类的关系只是消息的消费者和消息之间的依赖关系,并不是类内部属性和方法之间的紧密关联关系。。 updateOrder,saveOrder 为什么是无状态的?,恰恰相反,对于order而言,这两个防范恰恰是对order状态的确认.先看一下为什么要updateOrder? 是为了放入数据库么?不是?只是做一种确认,确认我order在n天后没有被别人edit过的话,他还是现在我确认的状态.所以完全可以做order.update(); order.save();都是对自身状态的刷新,从不稳定状态到稳定状态。 再来看看orm框架的目标是什么,就是为了让它的client看到的是对象。我拿到了order 我就可以order.getItem();这不就是hibernate 等orm框架 所努力的方向么而不是orderADO.getitem(connection,order,getID());当开始从数据库拿到order时候:order的状态是持久的,order.setProperty();后它的状态有可能 是dirty的,通过噢仁的人。update();确保他的状态在that moment是一致的,恰恰是数据不同状态的切换阿 这是数据持久化的状态和业务逻辑无关。 |
|
返回顶楼 | |
发表时间:2005-03-23
引用 这是数据持久化的状态和业务逻辑无关。 这句话听得老茧都出来了,太学术化,讲个简单的:什么时候commit,和业务逻辑相关么,那些操作步骤是一个事务和业务逻辑相关么?拿到order 再去拿detail你用了hibernate的lazyload之后,区切换到纯粹的dao实现真的只要替换dao的实现么? //hibernate Order order =dao.getOrder(ID);; order.getItems();; //jdbc implement (当然你join的话另当别论了); Oder order =dao.getOrder(ID);; orderItems =dao.getOrderItem(orderID);; 还有类似可reachable的特性等? 很容易被替换? 为什么不是很容易,原因在于这些持久化的接口不是ado 可以轻松定义的了得,hibernate的实现提供了一些underground 的协议,是你和Hibernate之间的 大部分是由hibernate所维护的对象图提供的. 一个很简单的问题: orderDetial被拿出来edit之后之后再去update和业务逻辑相关么?如何进行持久化对业务其实很有侵入性的.和connection的rebound的过程,和一些check的过程,如果没有实现对象的自由导航,中间会大量的调用dao,否则的话像hibernate提供很强的对象间导航的能力。中间dao调用就会减少,替换dao的不用hibernate几乎是不可能的,除非不用任何导航能力! 现在的简单的单数据库的实现connection 本身控制着事务,事务本身是由业务决定的,持久化的操作,从那里开始,那里结束时完全是业务的一部分。 注:我说的都没有基于组件的分布式发布,没有把不同的组建发布在不同的服务器上,而且都是纯粹的bs结构,浏览器的客户端,没有fat client。 |
|
返回顶楼 | |
发表时间:2005-03-23
frankensteinlin 写道 引用 这是数据持久化的状态和业务逻辑无关。 这句话听得老茧都出来了,太学术化,讲个简单的:什么时候commit,和业务逻辑相关么,那些操作步骤是一个事务和业务逻辑相关么?拿到order 再去拿detail你用了hibernate的lazyload之后,区切换到纯粹的dao实现真的只要替换dao的实现么? //hibernate Order order =dao.getOrder(ID);; order.getItems();; //jdbc implement (当然你join的话另当别论了); Oder order =dao.getOrder(ID);; orderItems =dao.getOrderItem(orderID);; 还有类似可reachable的特性等? 很容易被替换? 为什么不是很容易,原因在于这些持久化的接口不是ado 可以轻松定义的了得,hibernate的实现提供了一些underground 的协议,是你和Hibernate之间的 大部分是由hibernate所维护的对象图提供的. 一个很简单的问题: orderDetial被拿出来edit之后之后再去update和业务逻辑相关么?如何进行持久化对业务其实很有侵入性的.和connection的rebound的过程,和一些check的过程,如果没有实现对象的自由导航,中间会大量的调用dao,否则的话像hibernate提供很强的对象间导航的能力。中间dao调用就会减少,替换dao的不用hibernate几乎是不可能的,除非不用任何导航能力! 现在的简单的单数据库的实现connection 本身控制着事务,事务本身是由业务决定的,持久化的操作,从那里开始,那里结束时完全是业务的一部分。 注:我说的都没有基于组件的分布式发布,没有把不同的组建发布在不同的服务器上,而且都是纯粹的bs结构,浏览器的客户端,没有fat client。 正式因为ormapping框架的功能越来越强大,所以类似update,save这些功能不算业务逻辑,而事务,交给容器去管理吧。 |
|
返回顶楼 | |