我看到了一个类似的问题在SO上:如何更新聚合内的实体,但我仍然不确定用户界面应该如何与聚合内的实体交互。
假设我有一个User
,拥有一些Address
。User是聚合根,而Address只存在于聚合内部。
在网页界面上,用户可以编辑他的地址。基本上,发生以下情况:
- 用户在他的网页界面上看到了地址列表
- 他点击一个地址,被重定向到这个页面:
edit-address?user=1&address=2
- 在这个页面上,他得到一个表单,可以修改这个地址。
如果我们决定绕过聚合根,这将是很直接的:
- 我们将直接加载具有其
Id
的Address
- 我们将更新它,然后保存它
因为我们想按DDD方式做,我们有不同的解决方案:
要么我们请求User通过Id获取此Address:
address = user.getAddress(id);
address.setPostCode("12345");
address.setCity("New York");
em.persist(user);
这种方法的问题是,聚合根仍然对地址的处理没有更多的控制。它只返回一个对它的引用,所以与绕过聚合没有太大区别。
或者我们告诉聚合更新一个现有的地址:
user.updateAddress(id, "12345", "New York");
em.persist(user);
现在聚合根可以控制对该地址的操作,并且可以采取任何必要的行动来更新地址。
或者我们将地址视为一个值对象,不更新我们的
Address
,而是删除并重新创建它:user.removeAddress(id);
address = new Address();
address.setPostCode("12345");
address.setCity("New York");
user.addAddress(address);
em.persist(user);
这个解决方案看起来很优雅,但意味着一个地址不能成为实体。那么,如果需要将其视为实体,例如因为聚合根内的另一个业务对象引用了它,怎么办?
我相信我缺少了理解聚合概念以及它在实际场景中的应用的一些内容,请不要犹豫给出你的评论!
changeAddress()
方法。上面的示例是过于简化了,一个地址可能由十几个字段组成,包括街道名称、建筑物编号、LatLng
点表示地图上的精确位置等等。那么你建议怎么做呢?将所有这些参数放在方法参数中,还是从表单创建某种瞬态对象(也是Address
对象?),并将其作为参数传递给此方法? - BenMorel