关于DDD学习过程中的一些疑问

目前DDD关于概念,设计思想讨论了比较多。但在编码过程中还是涉及到了一些问题:

实体类中如果有个值对象的列表,那我要获取这个列表应该怎么做?
如账户实体中的角色列表: List<Role> getRoles();
a. 一种方式在实体中注入RoleRepository, 直接调用 roleRepository.getRoles(accountId)
b. 另一种是通过setRoles(roles)赋值。

问题1: 第一种方式,如果这个实体是从数据库中获得的,如何注入RoleRepository?
问题2: 如果通过setRoles(roles)赋值,那我要获得账户列表是不是要在AccountRepository 中去遍历一遍。因为这里涉及的数据有层次关系了。

也就是说 实体中嵌套值对象或实体时,应该如何组装这个实体(我用的是ibatis+mySQL做为数据存储)?

实体Entity中包含了若干组数据对象POJO的集合,所以要在实体中返回List<Role>,直接用实体调用DAO就行了,不用和Repository打交道

Repository是实体Entity的仓储,不是数据对象POJO的仓储

通常实体调用DAO,可以在实体中注入DAO的接口,这个Spring中很好实现。我现在的问题是如果这个实体是由ibatis返回的,那这个实体中的DAO应该是为null的。

所以我在考虑构建一个复杂的实体如何做?


// role实体
public class Role implements Serializable {

/** Serial version UID required for safe serialization. */
private static final long serialVersionUID = -5811523801082269593L;

private Integer id;

private String name;

private String description;

private Set<Permission> permissions = new HashSet<Permission>();

private PermissionRepository permissionRepository;

public Role(PermissionRepository permissionRepository) {
this.permissionRepository = permissionRepository;
}

// ..... gets,sets 忽略

/**
* @[author]return[/author] the permissions
*/

public Set<Permission> getPermissions() {
[author]return[/author] new HashSet<Permission>(this.permissionRepository.listPermissions(this.id));
}

/**
* @param permissions the permissions to set
*/

public void setPermissions(Set<Permission> permissions) {
if (permissions != null)
this.permissions = permissions;
}

public void addPermission(Permission permission) {
if (permission != null)
this.permissions.add(permission);
}

public boolean containsPermission(Permission permission) {
[author]return[/author] this.permissions.contains(permissions);
}
}

// ====== == Role 仓储
public class RoleRepositoryImpl extends GeneraliBatisSupport<Role> implements RoleRepository {

@Override
public List<Role> listRoles(Integer accountId) {
[author]return[/author] getSqlMapClientTemplate().queryForList(
"Role.LISTALL", accountId);
}

}

listRoles 返回的对象应该就是实体,但遍历出来的Role是没有注入permissionRepository 的。也就是直接调用role.getPermissions()方法会返回空指针
[该贴被babyba2009于2012-05-22 10:06修改过]

我是这样解决的,DAO<T>继承DAOBase

DAO<T> 是操作指定POJO的,比如dao.getInfo()
DAOBase 可以操作所有的POJO,比如dao.getInfo<T>()

如果在实体中要访问复杂的数据,直接用DAOBase就行了

继承方式我跟你是一样的。基类也用了泛型。

“如果在实体中要访问复杂的数据,直接用DAOBase就行了”, 参考我上面的代码,DAOBase在这种情况下是空指针的(由ibatis创建返回)。应该如何处理?
[该贴被babyba2009于2012-05-22 10:23修改过]

2012-05-22 09:51 "@babyba2009"的内容
通常实体调用DAO,可以在实体中注入DAO的接口,这个Spring中很好实现。我现在的问题是如果这个实体是由ibatis返回的,那这个实体中的DAO应该是为null的。 ...

这是现有框架应用DDD的最大问题所在了,而JdonFramework通过实体注入或者领域事件来解决这个问题的,等待这些开源框架更新吧。

banq, 目前有没有什么好的解决方案?

2012-05-23 10:17 "@babyba2009"的内容
banq, 目前有没有什么好的解决方案 ...

用Spring管理实体,与iBatis或Hibernate等实体对象区分开来,前者是领域模型的实体,后者是用于持久的实体,两者性质不同,用于持久的实体好像也是一个对象,其实只是表面上,本质隐式中这个实体受关系数据库影响的。
Martin Fowler厌倦ORM了,iBatis本质也是一个ORM。

至于领域实体和ORM实体之间数据如何复制,你可以做一个工厂进行转换。

还有其他做法,比如在领域实体中直接使用DAO或仓储接口,然后将仓储或DAO注射入领域实体中,这种方式导致领域模型与具体持久耦合:domain类型怎么访问数据集

其他方案:要么更换Jdon框架,要么自己改写Spring框架源码。 Jdon框架可以在Spring框架中使用的,相当于不去改写原有Spring源码,而是增加这部分功能支持。

或者用Scala等新语言。见这个案例


[该贴被banq于2012-05-23 12:06修改过]

2012-05-23 11:20 "@banq"的内容
还有其他做法,比如在领域实体中直接使用DAO或仓储接口,然后将仓储或DAO注射入领域实体中,这种方式导致领域模型与具体持久耦合:domain类型怎么访问数据集 ...

因为不太熟悉iBatis,所以之前一直没有回复

我使用了一个对象池来管理DAO的实例,当领域实体需要用到DAO时,直接将DAO的接口传给DAOPool,DAOPool会根据调用者的类型和DAO接口的类型返回最合适的实例,返回实例的匹配规则定义在XML文件里。

我用的是spring, 其实也不需要定义复杂DAOPool。只要解决重建实体时,如何注入DAO实例。 目前没有好的解决方案时,可能会采用实体工厂,值对象工厂。

2012-05-23 22:18 "@babyba2009"的内容
目前没有好的解决方案时,可能会采用实体工厂,值对象工厂。 ...

DDD设计决定了领域模型不能被ORM框架绑定。见2009年帖子:ORM已经是过去的事情
而直至今天,
Martin Fowler厌倦ORM了,终于承认ORM是计算领域的一场越南战争,陷入泥潭不能自拔,但是这么多年过去了,耽误贻害了多少系统呢?

在计算机软件层出不穷的过程中,我们经常因为执着于细节而忘记方向,只知道埋头插秧,结果方向都跑歪了。

新手路过,学习了。