锁定老帖子 主题:是否应该让实体类具备丰富的业务逻辑?
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (1)
|
|
---|---|
作者 | 正文 |
发表时间:2005-03-23
好,已经有4位同学参加投票了,先统计一下计票结果:
观点1: forumDao.update(...)不能写在Forum的deleteTopics()方法里面,而应该写在Forum类的外面 赞成票:3票 robbin赞成 七彩郎赞成 partech赞成(partech给出的代码,Forum的deleteTopics方法里面也没有update,他的Service代码就是做这个工作的) 观点2:forumDao.update(...)应该写在Forum的deleteTopics()方法里面,而不应该出现在外面 赞成票:1票 Archie赞成 |
|
返回顶楼 | |
发表时间:2005-03-23
public class ForumService implements IForumService extends Service { //这是一种简单的实现 public deletetopics(String forumID); { Init();; Forum forum = ForumRepository.findByID(forumID);; Rule rule = new Rule();; forum.deletetopics(rule);; commit();; } } public class Forum { private List topics; public deletetopics(Rule rule); { ... 如果这个topics符合删除逻辑 this.topics.remove(xxx);; // 这个才是业务逻辑。对数据库的读写不是业务逻辑,而是系统架构的I/O操作。 } } public class Service { ... protected void init(); { ... Session.init();; ... } protected void commit(); { ... Session.commit();; ... } ... } public class Session { static public void commit(); { ... Session.instance();.unitOfWork.commit();; ... } } TO Archie Service和Forum统统都不指向数据库。 |
|
返回顶楼 | |
发表时间:2005-03-23
sigh, 竟然被robbin离题成这个样子, 那么偶就跟着离题吧......
假设用户更新了某个topic的主题以后: topic.setSubject("new subject"); 需要把新的状态持久化到数据库 第一种模型的观点是 弄一个其他东东(TopicManager/TopicService),调用一下: topicManager.update class TopicManager { void update(Topic topic); { this.dao.update(topic);; } } 第二种模型的观点是 Topic本身最好有一个update的方法: topic.update();; class Topic { void update(); { this.dao.update(this);; } } 那么假设除了持久话以外, 还有重新建立全文搜索索引的问题, 那么第一种模型就得改成: class TopicManager { void update(Topic topic); { this.dao.update(topic);; this.indexer.reindex(topic);; } } class Topic { void update(); { this.dao.update(this);; this.indexer.reindex(this);; } } 都看起来很不爽......模型1需要多一个XXXManager, 模型2需要在实体对象引入2个基础设施(dao和indexer) 七彩狼 写道 CRUD是业务逻辑吗?我觉得不是。 CRUD应该在业务逻辑中吗?我觉得不应该。 CRUD应该出现在DM中吗?我也觉得不应该。 同样的偶的疑问也出来了: 建立全文索引是业务逻辑嘛? 偶觉得不是. 建立全文索引应该在业务逻辑中? 偶觉得不应该. 建立全文索引应该出现在DM中嘛? 偶觉得也不应该. 业务逻辑明明只有一句嘛: topic.setSubject("new subject"); DDD鼓吹的就是第2种模型吗? 偶觉得不是的, 假如有这些方法: topic.markModified(); topic.markNew(); topic.markDeleted(); 让dao和indexer都能够监听到这些事件, 在整个script执行完毕以后, 再执行对应的update/create/delete, reindex/newindex/deleteindex 这样topic本身只用知道调用markModified, 至于由谁会进行什么样的处理, 就不是业务逻辑所关心的了. 这样的做法在DDD里面好像称为Unit Of Work, 那么这种做法能称为模型3么? hehe |
|
返回顶楼 | |
发表时间:2005-03-23
:twisted:
readonly同学,我好不容易才把争论收敛起来,你偏偏又这么着急发散,你那个问题其实也是我这个帖子本来要提出的问题,先不要那么着急嘛,等我们先把观点澄清清楚了,统一命名了以后,再说那个问题。 经过这么几天来辛苦的争论,我明白了大家都对同一个名词产生了不同的理解,最后造成了自相残杀。所以先统一一下名词再说。 |
|
返回顶楼 | |
发表时间:2005-03-23
Readonly 写道 DDD鼓吹的就是第2种模型吗? 偶觉得不是的, 假如有这些方法: topic.markModified(); topic.markNew(); topic.markDeleted(); 让dao和indexer都能够监听到这些事件, 在整个script执行完毕以后, 再执行对应的update/create/delete, reindex/newindex/deleteindex 这样topic本身只用知道调用markModified, 至于由谁会进行什么样的处理, 就不是业务逻辑所关心的了. 这样的做法在DDD里面好像称为Unit Of Work, 那么这种做法能称为模型3么? hehe 这里的模型3,实际上非常接近partech的代码所描述的情况。 让我们做这样一种假设:假如我的系统架构,能够利用 AOP 来监听全部的对 Domain Model 的属性设置的修改。对于是否重建索引等纯数据库操作,采用在类似 Hibernate 配置文件中,描述的形式,那么我们就几乎可以做到建立纯粹的Domain Model,而且这个Domain Model 是不与系统架构相关联的,也是纯粹的POJO。我想,这就是我们的理想国吧。 |
|
返回顶楼 | |
发表时间:2005-03-23
七彩狼 写道 Readonly 写道 DDD鼓吹的就是第2种模型吗? 偶觉得不是的, 假如有这些方法: topic.markModified(); topic.markNew(); topic.markDeleted(); 让dao和indexer都能够监听到这些事件, 在整个script执行完毕以后, 再执行对应的update/create/delete, reindex/newindex/deleteindex 这样topic本身只用知道调用markModified, 至于由谁会进行什么样的处理, 就不是业务逻辑所关心的了. 这样的做法在DDD里面好像称为Unit Of Work, 那么这种做法能称为模型3么? hehe 这里的模型3,实际上非常接近partech的代码所描述的情况。 让我们做这样一种假设:假如我的系统架构,能够利用 AOP 来监听全部的对 Domain Model 的属性设置的修改。对于是否重建索引等纯数据库操作,采用在类似 Hibernate 配置文件中,描述的形式,那么我们就几乎可以做到建立纯粹的Domain Model,而且这个Domain Model 是不与系统架构相关联的,也是纯粹的POJO。我想,这就是我们的理想国吧。 是啊,到哪里找个例子呢? |
|
返回顶楼 | |
发表时间:2005-03-23
我先来总结和澄清一下:
第一、只有getter/setter的纯数据类是不可取的 这一点所有的人都达成了共识,没有异议的。前面有个同学提出,他们的Hibernate框架下实体类就是只有getter/setter,再也没有其他东西了,要说明的是,这种用法是不对的。纯数据类肯定是贫血的。 前面的误解在于Archie和partech误认为第一种模型下的持久化实体类只有getter/setter,实际上实体类还有其他的逻辑的,请参考readonly那个塞入了时间判断的类,后面Forum类的deleteTopics等等例子。 通过后面大家亮出来代码,robbin,七彩狼,partech的观点都统一起来了。这也说明了这几天白白自相残杀了。这里要补充说明的是partech给出的代码来看,他所谓的Service实际上是业务逻辑对象(xxxManager)和DAO两者合并到一起去的东西,其实真正的Service指的是业务层的Facade,不过这都是枝节,这里不深入讨论了。 第二、带状态的实体类(或者叫做某些人讲的domain object)应该塞入哪些逻辑 所有人都同意应该塞入逻辑,但是问题在于应该塞入哪些逻辑? robbin给出来一个准则:不依赖于持久化的逻辑塞入,依赖于持久化的逻辑剥离。这一点,robbin,七彩狼,partech都同意。但是Archie对此持有不同的看法:Archie认为即使是依赖于持久化的逻辑也必须放在实体类里面。所以现在问题的分歧就已经很明确了。 Martin Fowler究竟持何种观点,或者其他的什么观点我不是很清楚,我感觉他的观点是倾向于Archie的。现在持第一种观点的人认为把依赖持久化的逻辑放在实体类(或者说domain object)是不合理的,partech的说法就是这些依赖持久化的东西不叫做业务逻辑,而叫做服务。而持第二种观点的人认为这样的domain model才不贫血,才OO。 最后Readonly提出,目前第二种观点对外部的DAO,Index依赖太多,可以考虑使用Interceptor来透明的解决依赖性问题。 |
|
返回顶楼 | |
发表时间:2005-03-23
robbin 写道 我先来总结和澄清一下:
第一、只有getter/setter的纯数据类是不可取的 这一点所有的人都达成了共识,没有异议的。前面有个同学提出,他们的Hibernate框架下实体类就是只有getter/setter,再也没有其他东西了,要说明的是,这种用法是不对的。纯数据类肯定是贫血的。 前面的误解在于Archie和partech误认为第一种模型下的持久化实体类只有getter/setter,实际上实体类还有其他的逻辑的,请参考readonly那个塞入了时间判断的类,后面Forum类的deleteTopics等等例子。 通过后面大家亮出来代码,robbin,七彩狼,partech的观点都统一起来了。这也说明了这几天白白自相残杀了。这里要补充说明的是partech给出的代码来看,他所谓的Service实际上是业务逻辑对象(xxxManager)和DAO两者合并到一起去的东西,其实真正的Service指的是业务层的Facade,不过这都是枝节,这里不深入讨论了。 第二、带状态的实体类(或者叫做某些人讲的domain object)应该塞入哪些逻辑 所有人都同意应该塞入逻辑,但是问题在于应该塞入哪些逻辑? robbin给出来一个准则:不依赖于持久化的逻辑塞入,依赖于持久化的逻辑剥离。这一点,robbin,七彩狼,partech都同意。但是Archie对此持有不同的看法:Archie认为即使是依赖于持久化的逻辑也必须放在实体类里面。所以现在问题的分歧就已经很明确了。 Martin Fowler究竟持何种观点,或者其他的什么观点我不是很清楚,我感觉他的观点是倾向于Archie的。现在持第一种观点的人认为把依赖持久化的逻辑放在实体类(或者说domain object)是不合理的,partech的说法就是这些依赖持久化的东西不叫做业务逻辑,而叫做服务。而持第二种观点的人认为这样的domain model才不贫血,才OO。 最后Readonly提出,目前第二种观点对外部的DAO,Index依赖太多,可以考虑使用Interceptor来透明的解决依赖性问题。 Robbin同学,我也希望大家能够统一观点,但是你现在下结论就太早了。 我的ForumService对象是服务层的对象不是业务层的对象。 刚才我给出的例子是简单的实现。业务服务往往不会是只改变一个对象这么简单,同时改变多个对象的例子很常见。 对于跨越操作多个业务对象的操作,需要引入控制类。 不明白你说的准则“不依赖于持久化的逻辑塞入”指的什么?订单Order的下订单的操作是否属于Order对象,还是属于OrderManager? |
|
返回顶楼 | |
发表时间:2005-03-23
这是我在Domain Model探索中的论述,修改了一下.
Service层 现在我们向上看看将业务层包裹的服务层。 服务层是架设在应用层和业务层的桥梁,用来封装对业务层的访问,因此 可以把服务层看作中介,充当两个角色: 1.实现应用层接口要求的接口; 2.作为业务层的外观。 服务层的典型调用如下: public interface CustomerServices { void openCustomer(CustomerInfo cutomerInfo);; void customerLostReport(String customerCode,Date expiringDate,String remark);; CutomerBasicInfo getCutomerBasicInfo(String customerCode);; ... } public class CustomerServicesImpl extends ServiceFacade implements CustomerServices { ... public void openCustomer(CustomerInfo cutomerInfo); { try { init();; OpenCustomerAct openCustomerAct = new OpenCustomerAct(customerInfo.name, customerInfo.code, customerInfo.address, customerInfo.plainpassword ... );; openCustomerAct.run();; commit();; } catch(Exception e); { throw ExceptionPostprocess(e);; } } } public class OpenCustomerAct extends CustomerAct { ... public void override doRun(); { Customer customer = Customer.create(...);; CapitalAccount capitalAccount = CapitalAccount.create(customer,...);; capitalAccount.deposit(...);; OpenCustomerLog.create(this);; } ... } |
|
返回顶楼 | |
发表时间:2005-03-23
引用 Robbin同学,我也希望大家能够统一观点,但是你现在下结论就太早了。
我的ForumService对象是服务层的对象不是业务层的对象。 刚才我给出的例子是简单的实现。业务服务往往不会是只改变一个对象这么简单,同时改变多个对象的例子很常见。 对于跨越操作多个业务对象的操作,需要引入控制类。 不明白你说的准则“不依赖于持久化的逻辑塞入”指的什么?订单Order的下订单的操作是否属于Order对象,还是属于OrderManager? 我并不希望大家观点统一,我也没有下什么结论,如果你仔细看看这个帖子我最前面的发贴,就应该明白我在第一贴处就已经引用potian的话给出结论了。我发起这个帖子的目的就是希望听取一下Archie那种观点究竟会带来什么实际的编程方面的好处(至于所谓的专家的权威论断,更加OO什么的空话我不想听)。 但是非常令我遗憾的是,接下来的讨论根本就是偏离我发的主题贴的,搞成了纯数据类贫血不贫血的讨论去了,然后大家针对同一个名词有自己不同的理解从而造成了无谓的争论。最后直到亮出了代码才搞清楚,说实话这个讨论一直到现在才开始真正我希望讨论的内容,前面全都是浪费时间了。 至于你的所谓服务层什么的,那是另一个话题,我不会在这里帖子里面讨论这个问题,你想讨论可以另外开贴。 |
|
返回顶楼 | |