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

12-05-21 babyba2009

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

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

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

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

4
gameboyLV
2012-05-22 09:42

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

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


babyba2009
2012-05-22 09:51

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

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

babyba2009
2012-05-22 10:01

// 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);
	}

}
<p class="indent">


listRoles 返回的对象应该就是实体,但遍历出来的Role是没有注入permissionRepository 的。也就是直接调用role.getPermissions()方法会返回空指针

[该贴被babyba2009于2012-05-22 10:06修改过]

gameboyLV
2012-05-22 10:08

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

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

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

babyba2009
2012-05-22 10:22

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

“如果在实体中要访问复杂的数据,直接用DAOBase就行了”, 参考我上面的代码,DAOBase在这种情况下是空指针的(由ibatis创建返回)。应该如何处理?

[该贴被babyba2009于2012-05-22 10:23修改过]

banq
2012-05-23 09:23

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


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

babyba2009
2012-05-23 10:17

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

banq
2012-05-23 11:20

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修改过]

gameboyLV
2012-05-23 12:30

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


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

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

babyba2009
2012-05-23 22:18

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

banq
2012-05-31 09:13

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


DDD设计决定了领域模型不能被ORM框架绑定。见2009年帖子:ORM已经是过去的事情
而直至今天,

Martin Fowler厌倦ORM了,终于承认ORM是计算领域的一场越南战争,陷入泥潭不能自拔,但是这么多年过去了,耽误贻害了多少系统呢?

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

huting0211
2012-08-23 22:44

新手路过,学习了。