论坛首页 Java企业应用论坛

是否应该让实体类具备丰富的业务逻辑?

浏览 67207 次
精华帖 (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赞成
0 请登录后投票
   发表时间: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统统都不指向数据库。
0 请登录后投票
   发表时间: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
0 请登录后投票
   发表时间:2005-03-23  
:twisted:

readonly同学,我好不容易才把争论收敛起来,你偏偏又这么着急发散,你那个问题其实也是我这个帖子本来要提出的问题,先不要那么着急嘛,等我们先把观点澄清清楚了,统一命名了以后,再说那个问题。

经过这么几天来辛苦的争论,我明白了大家都对同一个名词产生了不同的理解,最后造成了自相残杀。所以先统一一下名词再说。
0 请登录后投票
   发表时间: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。我想,这就是我们的理想国吧。
0 请登录后投票
   发表时间: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。我想,这就是我们的理想国吧。


是啊,到哪里找个例子呢?
0 请登录后投票
   发表时间: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来透明的解决依赖性问题。
0 请登录后投票
   发表时间: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?
0 请登录后投票
   发表时间: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);;
}
...
} 
 
0 请登录后投票
   发表时间:2005-03-23  
引用
Robbin同学,我也希望大家能够统一观点,但是你现在下结论就太早了。
我的ForumService对象是服务层的对象不是业务层的对象。
刚才我给出的例子是简单的实现。业务服务往往不会是只改变一个对象这么简单,同时改变多个对象的例子很常见。
对于跨越操作多个业务对象的操作,需要引入控制类。

不明白你说的准则“不依赖于持久化的逻辑塞入”指的什么?订单Order的下订单的操作是否属于Order对象,还是属于OrderManager?


我并不希望大家观点统一,我也没有下什么结论,如果你仔细看看这个帖子我最前面的发贴,就应该明白我在第一贴处就已经引用potian的话给出结论了。我发起这个帖子的目的就是希望听取一下Archie那种观点究竟会带来什么实际的编程方面的好处(至于所谓的专家的权威论断,更加OO什么的空话我不想听)。

但是非常令我遗憾的是,接下来的讨论根本就是偏离我发的主题贴的,搞成了纯数据类贫血不贫血的讨论去了,然后大家针对同一个名词有自己不同的理解从而造成了无谓的争论。最后直到亮出了代码才搞清楚,说实话这个讨论一直到现在才开始真正我希望讨论的内容,前面全都是浪费时间了。

至于你的所谓服务层什么的,那是另一个话题,我不会在这里帖子里面讨论这个问题,你想讨论可以另外开贴。
0 请登录后投票
论坛首页 Java企业应用版

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