论坛首页 Java企业应用论坛

贫血的Domain Model

浏览 46145 次
该帖已经被评为精华帖
作者 正文
   发表时间:2008-05-10  
public class Employee {

    private long id;
    private int salary;
    private String name;
    private Department department;
    private RichSet<Task> tasks = new DefaultRichSet<Task>();

    public Employee(String name, int salary, Department department) {
        this.name = name;
        this.salary = salary;
        this.department = department;
    }

    protected Employee() {

    }

    public long getId() {
        return id;
    }

    public int getSalary() {
        return salary;
    }

    public Department getDepartment() {
        return department;
    }

    public Task assign(String taskName) {
        Task task = new Task(taskName, this, new Date());
        tasks.add(task);
        return task;
    }

    public RichSet<Task> getProcessingTasks() {
        return tasks.find("startTime").le(new Date()).find("endTime").isNull();
    }

    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Employee employee = (Employee) o;

        if (name != null ? !name.equals(employee.name) : employee.name != null) return false;

        return true;
    }

    public int hashCode() {
        return 31 * (name != null ? name.hashCode() : 0);
    }
}
0 请登录后投票
   发表时间:2008-05-10  
ronghao 写道
在我实际的编程里,Domain对象里大量注入了DAO,我并没有觉得有什么不好,好处在于带来了一致的编程体验,唯一的问题在于给测试带来了麻烦,单元测试需要写很多stub。在特定于工作流引擎的情况下,很多同事主张用事件的方式来解除Domain对象与DAO的耦合,但是我觉得没有必要。
楼主的解决方案我觉得还是存在一定局限性的。比如如果Domain对象的业务方法需要执行业务逻辑并插入或更新数据时。

同意,注入DAO没什么不好。测试的时候起一个内存数据库就好了。再弄几个db fixture,状态准备也一样轻松搞定。

执行业务逻辑就用代码写好了。更新数据就是修改自己的状态。service会去最后把domain对象save回去的,因为hibernate可以遍历对象图找出改动,所以这个我们不用操心。
插入数据可以通过添加元素到一个特殊的RichList来实现。
Department department = new Department("R&D");
department.hire("taowen", 100);
repository.of(Department.class).add(department);

public interface Repository {

    <T> RichList<T> of(Class<T> entityClass);
}

简单来说,就是把一张表抽象为一个RichList。添加记录就是add,删除记录就是remove。这个RichList在domain中使用,但是domain并不用担心这个list是怎么构建出来的。在单元测试的时候可以使用一个InMemory的List,在产品代码中这个List是一个包装着Hibernate Session的家伙。
0 请登录后投票
   发表时间:2008-05-10  
Martin Fowler的回复
引用

Sounds rather like Linq.

Certainly adding this kind of query logic is part of getting people away from Anemia, so it's a useful option. The Query Object in P of EAA is roughly similar kind of idea - build queries in domain terms and then translate them to either/or in memory navigation or SQL.
0 请登录后投票
   发表时间:2008-05-10  
got it, thanks
0 请登录后投票
   发表时间:2008-05-10  
taowen 写道

同意,注入DAO没什么不好。测试的时候起一个内存数据库就好了。再弄几个db fixture,状态准备也一样轻松搞定。

执行业务逻辑就用代码写好了。更新数据就是修改自己的状态。service会去最后把domain对象save回去的,因为hibernate可以遍历对象图找出改动,所以这个我们不用操心。
插入数据可以通过添加元素到一个特殊的RichList来实现。
Department department = new Department("R&D");
department.hire("taowen", 100);
repository.of(Department.class).add(department);

public interface Repository {

    <T> RichList<T> of(Class<T> entityClass);
}

简单来说,就是把一张表抽象为一个RichList。添加记录就是add,删除记录就是remove。这个RichList在domain中使用,但是domain并不用担心这个list是怎么构建出来的。在单元测试的时候可以使用一个InMemory的List,在产品代码中这个List是一个包装着Hibernate Session的家伙。

nice! 可是我怎么总感觉RichList像个变了性的通用DAO呢,也就是用它将domain与数据持久化代码进行了一次隔离。呵呵
0 请登录后投票
   发表时间:2008-05-10  
对啊,就是在Domain <-> Hibernate之间建立了一个隔离层。只不过它本身是一个collection而已。其实自身是一个generic dao。
0 请登录后投票
   发表时间:2008-05-10  
另一个方面的问题:一个主业务Domain Object,其中可能包含20来个字段,可能需要和多个其他的Domain Object关联。这个时候,按照Rich Domain Object的理论和你的实现,可以把这些查询逻辑或者持久化逻辑全部封装在Domain Object的内部。那么这个Domain Object会有多少行?在团队合作中,如何保持它内部语义的不重复性?
0 请登录后投票
   发表时间:2008-05-10  
按照马丁的意思,Rich Domain Object无非是想程序更好维护,那我想,既然这样想了,那就直奔主题,不要被隔离的思想束缚住,Domain Object就直接引用hibernate session或者dao甚至jdbc connection,就好了.看看达到这个更好维护的目的没有。老是想着隔离,隐藏,呢,创建出一些新的隔离对象,干扰了视线。
0 请登录后投票
   发表时间:2008-05-10  
查询逻辑,比如说对一个collection的过滤是应该封装在domain中的。持久化逻辑并不是什么逻辑。持久化只是一种domain的存在形式。
关于Domain对象太大这个问题,你说有什么问题呢?要具体问题具体分析吧。团队合作,更加超出了技术能够解决的范畴了。
0 请登录后投票
   发表时间:2008-05-10  
nihongye 写道
按照马丁的意思,Rich Domain Object无非是想程序更好维护,那我想,既然这样想了,那就直奔主题,不要被隔离的思想束缚住,Domain Object就直接引用hibernate session或者dao甚至jdbc connection,就好了.看看达到这个更好维护的目的没有。老是想着隔离,隐藏,呢,创建出一些新的隔离对象,干扰了视线。

同意。其实domain对象和数据库绑定,直接用session没啥问题。ActiveRecord不也这么干的嘛。人家连字段都是数据库的。
0 请登录后投票
论坛首页 Java企业应用版

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