DDD:实体作为价值对象的工厂?

时间:2014-10-21 14:50:26

标签: domain-driven-design

在DDD中有一个创建值对象的实体是否有意义?

我有QuestionAnswers。问题是一个实体,而答案是价值对象。问题持有答案。用户创建问题和答案。

[A]有人说:question.createAnswer()。这样,只有问题才能解决问题。这样我们就可以避免在没有问题的情况下得到答案。然而 - 这不是创造答案的问题,而是用户。

我个人感觉不到这一点 - 对我而言,创建Answer并将其分配给问题是有意义的。这不是商业逻辑,对吗?

[B}我更喜欢以这是自然流动:

Question q = new Question();
Answer a = new Answer(q);   // answer can't exist without a question

[C]其他一些人也同意:

Question q = new Question();
Answer a = new Answer();
q.addAnswer(a);

这是B的“宽松”版本,因为Answer可能不存在Question;从我的观点来看似乎不行。

有什么智慧吗?

2 个答案:

答案 0 :(得分:2)

如果您遵循领域驱动设计原则,“问题”将是实体和“答案”,价值对象和问题的属性。问题将有一个方法setAnswer(假设每个问题只有一个答案),它是你用来指定问题答案的。

在伪代码中,这是定义类的方式:

public class Question {
     String question;
     Answer answer;

     public Question(String question) {
         this.question = question;
     }

     public setAnswer(String answer) {
         this.answer = new Answer(answer);
     }

}

public class Answer {
     String answer;

     public Answer(String answer) {
         this.answer = answer;
     }
}

这就是你将如何使用它们:

Question q = new Question("What is the capital of Australia?");
q.setAnswer("Canberra");

// use a repository for the Question Entity to persist the question instance
QuestionRepository.add(q);

如果您的要求要求跟踪哪个用户添加了答案,那么您将需要添加名为UserId的值对象,该对象是另一个名为User的实体的属性。 (假设userid对每个用户都是唯一的)

public class UserId {
    String userid;
    public UserId(String userid) {
        this.userid = userid;
    }
}

public class User {
    UserId userid;
    String firstName;
    String lastName;
    :
    :
}

以下是Answer值对象的外观:

public class Answer {
     String answer;
     UserId authorUserId;

     public Answer(String answer, UserId userid) {
         this.answer = answer;
         this.authorUserId = userid;
     }
}

问题中的SetAnswer方法需要修改为:

     public setAnswer(String answer, UserId authorUserId) {
         this.answer = new Answer(answer, authorUserId);
     }

最后,要使用它(假设userid是一个用当前登录用户的用户ID填充的UserId类型的变量):

Question q = new Question("What is the capital of Australia?");
q.setAnswer("Canberra", userid);

答案 1 :(得分:0)

也许你需要推断Question作为聚合物而不是OO代表一个具体化的存在/对象。确定的问题并不能在现实世界中创建自己的答案,但Question 聚合可以完美地公开Answer(...)(如动词中)反映事实的方法客户端代码订单聚合以合并用户刚刚输入的答案。

选项[A]和[B]对我来说似乎同样好,如果Answer中存在需要强制执行Question的数据的不变量,则优先选择[A],因为[B]可能意味着两者之间的双向关系。如果您认为聚合设计解决了“不能没有”规则,那么[C]也是可能的(答案必须与问题一起加载,随之删除)而不是开发人员级别的预防措施。

总的来说,我认为这些都是细节,还有更重要的事情,例如确保Aggregate的设计考虑了生产中会发生的事务。例如,包含来自所有用户的Answers的单个“问题#35”聚合根可能会在高度协作的上下文中造成并发问题。