我正在尝试使用DDD建模一个简单的应用程序。
考虑以下简化代码,其中的想法是隐藏注释,如果隐藏了其父Post:
class Post {
private $hidden;
public function isHidden() {
return $this->hidden;
}
}
class Comment {
private $post;
private $hidden;
public __construct(Post $post) {
$this->post = $post;
}
public function isHidden() {
if($this->hidden || $this->post->isHidden()){
return true;
}
}
}
我正在考虑将评论和帖子视为总体根源。
在阅读了有关引用聚合根的ID而不是引用之后,我已将注释引用更改为Post ID,并因为这行代码而立即在我的单元测试中发现错误:
$this->post->isHidden()
这种类型的逻辑不应该在Domain层吗?这可能是我设计聚合的方式的问题吗?
答案 0 :(得分:0)
如果hidden
和Post
的{{1}}属性必须始终保持一致,那么您可能需要为大型群集聚合建模。为了减少并发失败(例如,允许同时添加2条注释),您可以调整持久性机制以允许集合不受约束地增长。但是,这通常是可以最终保持一致的规则。如果隐藏Comment
和Post
之间的延迟时间是否真的很重要?
选择最终一致性,Comment
和Post
是他们自己的AR。当Comment
被隐藏时,Post
事件将被发送到消息传递机制,订阅者将负责使各个关联的PostHidden
AR保持一致。
另请注意,您可能根本不需要同步Comment
和Post.hidden
。由于Comment.hidden
可能仅在Comment
的上下文中出现,因此我并未真正看到用户界面如何看到隐藏Post
的{{1}}。避免同步Comment
标记实际上允许取消隐藏Post
,同时将hidden
恢复到Post
隐藏之前的状态,而无需执行任何操作
答案 1 :(得分:0)
首先,我必须同意plalx关于需要同步Post
以及Comment
中隐藏标志的最后一段。可以假设UI会查看Post
并意识到它是隐藏的,而不是费心取/显示注释?但我很欣赏你可能只是在一个简单的例子上练习DDD理论。
我也同意他对最终一致性所说的话。但是,就本练习而言,我认为没有必要添加它所需的基础设施,可以采取更简单的方法。
我想说有两种方法可以做到这一点,选择取决于每个帖子可能有多少评论。免责声明:我是C#程序员,请原谅我,如果php语法错误(我假设它是php?)
如果每封帖子不太可能有数百条评论,我会将Comment
建模为Post
的子实体,其中Post
是唯一的聚合根。这样隐藏的注释不变量很容易实现:
class Post {
private $hidden;
private $comments;
public function isHidden() {
return $this->hidden;
}
public function hide(){
$hidden = true;
foreach ($comments as $comment){
$comment.hide();
}
}
public function addComment($comment){
$comments.add($comment);
}
}
如果帖子中可能会添加数百条评论,那么您需要将其建模为单个聚合。否则,Post聚合将变得太大,也许更重要的是(并且作为plalx指出),您可能会在同时添加多个注释的Post
聚合上获得并发冲突。
这样做会涉及使用Domain Service来处理逻辑,而不是调用者使用聚合本身的方法:
class PostService {
private $postRepository;
private $commentRepository;
public function hidePost($postId) {
$post = $postRepository.GetById($postId);
$post.hide();
$postRepository.save($post);
//Method 1: update each comment
$comments = $commentRepository.GetCommentsByPostId($postId);
foreach($comments as $comment){
$comment.hide();
$commentRepository.save($comment);
}
//Method 2: create specific update method on repository with performant update query
$commentRepository.hideCommentsForPost($postId);
}
}
请注意,聚合上的hide()
方法无法公开使用。在C#中,这些被称为internal
方法,这意味着只有同一个程序集中的代码才能调用它们:重点是调用者被迫使用PostService
来隐藏帖子,而不是$post.hide()
AR直接。
另请注意,您不应直接在AR中引用其他AR。您应该通过Id引用其他AR。 See this for more info。