论坛首页 Java企业应用论坛

再次小结领域模型的种种观点

浏览 146169 次
该帖已经被评为精华帖
作者 正文
   发表时间:2005-12-16  
其实说起来,我赞同robbin的意见,目前domain obj和manager or service的这个划分做法是合适的,不同的是我们使用的是失血模型,因为在所处的行业里,各种概念都还处于待沉淀,待精化的阶段,这也意味着数据的多变和业务的多变,而为了适应两者分别的变化,我们采用失血模型和Service两层来区分处理两者的变化。
0 请登录后投票
   发表时间:2005-12-16  
wolfsquare 写道
其实说起来,我赞同robbin的意见,目前domain obj和manager or service的这个划分做法是合适的,不同的是我们使用的是失血模型,因为在所处的行业里,各种概念都还处于待沉淀,待精化的阶段,这也意味着数据的多变和业务的多变,而为了适应两者分别的变化,我们采用失血模型和Service两层来区分处理两者的变化。

毫无疑问,目前如果项目拿来就做,这样的做法是最合适,最成熟。
但是我们现在的讨论是在理论的高度,本身开这个帖子很大一个原因是我们看到一些新的似乎更理想的oo的编程,我们的框架、技术等都在朝这样的方向前进,我们的想法为什么还要停留在原地?
robbin对充血模型的缺点总结也总结得很好,但问题摆在那边是需要解决的,乐观得看,我觉得这些问题都是会被解决的。
0 请登录后投票
   发表时间:2005-12-16  
nkoffee 写道
robbin 写道
引用
这样的情况
Accounts.getAverageBalance() 比 AcountManager.getAverageBalance() 更好些,
AccountManager更像是关于Account这个modul的业务脚本,
而Accounts是建立在这些业务脚本上更高一层次的OO抽象,
两个干的事差不多,但是概念不同,
当工具足够强大后,我们的domain modul就无须为事务的特点所妥协(会自动合并,设置事务边界),
事务应该散布在整个domain modul里。


经过wolfsquare的启发,我明白account的这些无状态的被动操作其实都是bank领域对象的主动业务逻辑方法。如果外沿无限扩大的话,我们总可以消除所有的无状态被动操作,让系统只剩下单一的领域对象和DAO接口。

叫Accounts确实比AccountManager来得舒服那么一点点,但是概念没有什么不同,都是用来分离bank的职责的。

现在spring的声明式事务已经强大到自动合并,设置事务边界了,事务确实可以散落在domain model里面,但是就算这样,你还是少不了Accounts。

我们应该可以看到我们的工具正在朝这样的方面努力,所以我们也需要更开阔得看这些问题,我们的domain modul也可以应该也能够丰富到很丰富,我觉得我们今天讨论还是得到原先的结论,是有些保守了。
Accounts是必须的,因为他本身就是这个modul里的一部分,在整个modul里每个modul都各司其职,但是不应该以事务来再区分modul里的这部分和那部分(xxx and xxxManager)。这是我们原来的一种妥协,我们现在就是置疑这种妥协的必要性。


按照Accounts和Account两个Class的二元结构来表达Account领域模型,我认为这个充血模型是比较合理的。

我先前提出把包含持久化逻辑的操作都划分到AccountManager(或者叫做Accounts)里面,确实如你所说,是基于事务的划分。单纯从OO的角度来考虑,不够完备,是贫血的。

但是从目前阶段来看,对于domain object的post-initiation技术还不完备,Spring2.0和dynamic AspectJ还没有推出(nuts弄出来好多Factory,引入injector让我感觉也很别扭),充血模型从技术上来说,还无法优雅的实现。

如果Spring2.0和dynamic aspectJ普及了,我很愿意尝试这种充血模型,但是现在技术上实现不了,我不得不妥协。
0 请登录后投票
   发表时间:2005-12-16  
使用AOP静态配置的cutpoint也能完成这样的充血模型实现,不太清楚为什么要引入动态的概念。
而且,即使使用了这种模型,业务方法domain object和service还是要重复声明,麻烦。
再者,怎么控制web层不能随便调用业务方法?
0 请登录后投票
   发表时间:2005-12-16  
我正在做一个Nuts和aspectj结合的post instantiation。等做好了贴出来。
0 请登录后投票
   发表时间:2005-12-16  
robbin 写道


二、贫血模型

贫血模型请看
http://forum.iteye.com/viewtopic.php?t=11712
中列举的第二种模型,简单来说,就是domain ojbect包含了不依赖于持久化的领域逻辑,而那些依赖持久化的领域逻辑被分离到Service层.
Service(业务逻辑,事务封装) --> DAO ---> domain object

这种模型的优点:
1、各层单向依赖,结构清楚,易于实现和维护
2、设计简单易行,底层模型非常稳定
这种模型的缺点:
1、domain object的部分比较紧密依赖的持久化domain logic被分离到Service层,显得不够OO
2、Service层过于厚重


我以为自己对贫血模型理解错了,马上又把老马的文章拿来看一遍http://martinfowler.com/bliki/AnemicDomainModel.html

我觉得自己理解应该没错,贫血模型应该Domain Object本身只是数据的容积,不包含或者包含很少的业务逻辑, 而采用只提供静态方法的Manager实现业务逻辑(TransactionScript).这种方式没办法将OOAD和实现相对应,无法使用继承多态不利于系统的扩展,逻辑难于重用。

当然,很多系统都算不上企业级,很多企业级的系统也都被切分成一个一个的小系统,Rich Domain Model在这些小系统中是很难发挥作用的,从小系统的实用的角度来说,我并不排斥贫血模型。但是技术人员总归是得有些理想,理想我们可以把这些小的系统组合起来,或者整个企业有完整统一的领域层,所以我们坚持在这些小系统里面尝试Rich Domain Model。在我们的小系统里面,有些业务边界对象使用了Manager,边界对象在另外一个系统中可能有一个复杂的模型,但是在我的系统里面,可能只用到少量的静态逻辑。
0 请登录后投票
   发表时间:2005-12-16  
Readonly 写道
robbin 写道
好吧,那么我是web程序员,我从页面传一个id过来,要先load一下该Account,显示account的信息。那么请问:你提供给我什么API?是
account.getAccountById(id);
还是
accountService.getAccountById(id);
还是
accountDao.getAccountById(id);
?


new Account(id);


我以前就是用的这种方法,但是你的代码还是要给别人看的,我不能确保每个看我代码的家伙都能来javaeye看到这么好的帖子^_^

所以对于我来说,在很长的一段时间内,domain object 和Service都会在系统中存在

举个例子:

robbin说得WEB上提供id可以使用new Account(id);,如果是用户登陆呢?

难道是
new User(name,password) throws XXXException,YYYException
么?

User user=userService().getUserByName(name);
user.validatePass(pass);
user.logon();

这种代码,就是我所理解的service和user完美组合。
0 请登录后投票
   发表时间:2005-12-16  

User user=userService();.getUserByName(name);; 
user.validatePass(pass);; 
user.logon();; 



完美嘛?你如何处理用户不存在的情况?还不是要写恶心的if?
0 请登录后投票
   发表时间:2005-12-16  
我是比较同意robbin的观点的,举个登录的例子:

EmployeeService的实现:
    /* (non-Javadoc);
     * @see com.bearingpoint.gdc.service.EmployeeService#doLogin(java.lang.String, java.lang.String);
     */
    public Employee doLogin(String name, String password); throws ObjectNotFoundException, PasswordNotMatchException {
        Employee employee = null;
        List result = employeeDAO.getEmployeeByName(name);;
        if(result.size(); == 0);
            throw new ObjectNotFoundException();;
        else {
            employee = (Employee);result.get(0);;            
            if(!employee.getPassword();.equals(password););
                throw new PasswordNotMatchException();;
        }
        return employee;
    }


DAO的实现:
    /* (non-Javadoc);
     * @see com.bearingpoint.gdc.dao.EmployeeDAO#getEmployeeByName(java.lang.String);
     */
    public List getEmployeeByName(String name); {
        String querySentence = "FROM Employee employee WHERE employee.name = :name";
        Query query = getSession();.createQuery(querySentence);;
        query.setParameter("name", name);;
        return query.list();;
    }


Action更简单:
/* (non-Javadoc);
     * @see com.opensymphony.xwork.Action#execute();
     */
    public String execute(); throws Exception {        
        employee = employeeService.doLogin(employee.getName();, employee.getPassword(););;
        
        //put the employee into session
        ServletActionContext.getContext();.getSession();.put("currentEmployee", employee);;
        
        return SUCCESS;
    }


结构层次很清晰,DAO就负责数据库操作,Service层处理逻辑。万一你的业务逻辑发生扩展和变化,也只要修改和扩展你的Service实现,与其他层次无关。同时,Service层总是接受事务的控制。

按照firebody的观点,莫非我的doLogin的逻辑要写在我的Employee类里面?然后new Employee(String name, String password) throw xxxException?这太恶心了。
0 请登录后投票
   发表时间:2005-12-16  
downpour 写道

User user=userService();.getUserByName(name);; 
user.validatePass(pass);; 
user.logon();; 



完美嘛?你如何处理用户不存在的情况?还不是要写恶心的if?


UserNotFoundException

目前系统里最多的就是Action和Exception,的确烦恼

完美只是我个人感觉,因为从最开始在jsp中用userUtil开始到现在这种,这个是最能被人接受的
0 请登录后投票
论坛首页 Java企业应用版

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