我在实体设计方面遇到了问题。正如我所读到的,当您设计DDD实体时,构造函数应该包含实体“存在”所需的值。例如,在我正在处理的域中,如果没有Section和Level,则Class实体不能存在:
public class Class
{
public Class(short id, string section, Level level)
{
ID = id;
Section = section;
Level = level;
}
//
// Properties
//
public short ID { get; private set; }
public string Section { get; private set; }
public Level Level { get; private set; }
//
// Methods
//
public static IList<Class> GetClassesByTeacher(short teacherID)
{
List<Class> classes = new List<Class>();
classes.Add(new Class(1, "a", null));
classes.Add(new Class(2, "b", null));
classes.Add(new Class(3, "c", null));
return classes;
}
}
此处Level也是一个实体。由于我还没有完成设计,Level的构造函数也可能包含一个实体SchoolYear。困扰我的是我调用GetClassesByTeacher方法,我需要实例化一个类以及其他实体(Level,以及Level的构造函数中需要的SchoolYear)。
这是正确的吗?我想当我想调用这个方法时,这很麻烦。还有其他方法吗?我认为它是静态的,但其他人说可测性会受到影响。我不确定CQRS是否是我想要做的解决方案之一,因为我还没有读过太多关于它的内容,但如果是的话,除了我可以使用的CQRS之外是否还有其他技术,或者是去DDD的时候,这是怎么回事?或者我的实体设计不正确?
答案 0 :(得分:4)
你应该重新考虑你的域名模型,因为你实际上说它似乎有些不对劲。
我可以参考单一责任原则(SRP),其中任何类都应该有一个改变的理由。在您的示例中,如果我们向&#39; Class&#39;添加新字段会发生什么,我们将修改&#39; Class&#39;它本身就是正确的,但是如果我们认为列表应该是逆转顺序,或者如果你需要一种只考虑临时教师的新类型的清单会发生什么......你应该改变“等级”。但是&#39; Class&#39;与列表无关。
要回答你的问题,你可以看看Repository pattern。存储库是您可以要求这些类型的列表的地方。
我可能将Class分成两部分:
总结:
public class Class
{
public Class(short id, string section, Level level)
{
ID = id;
Section = section;
Level = level;
}
//
// Properties
//
public short ID { get; private set; }
public string Section { get; private set; }
public Level Level { get; private set; }
}
public class ClassRepository
{
private IList<Class> contents;
//
// Methods
//
public IList<Class> GetClassesByTeacher(short teacherID)
{
List<Class> classes = new List<Class>();
for (Class elem: contents) {
if (elem.getTeacher().equals(teacherID) {
classes.Add(elem);
}
}
return classes;
}
}
repository = new ClassRepository;
level1 = new Level();
repository.Save(new Class(1, "a", level1));
repository.Save(new Class(2, "b", level1));
repository.Save(new Class(3, "c", level1));
result = repository.GetClassesByTeacher(1);
还有其他细节,比如使用ClassRepositoryInterface并使用InMemoryClassRepository实现,只要一个老师开课,你就会错过课堂上的教师信息,如果不是,你可能会改变老师过滤等的方法等等。
我不是Java开发人员,代码也无法编译,但我希望你能理解。
答案 1 :(得分:3)
GetClassesByTeacher
方法确实属于某种存储库或服务类。您的Class
实体旨在表示现实世界中该事物的实例。实体并不意味着提供实例(例如,来自某些底层持久性) - 它们仅用于表示它们。 ClassRepository
可以将Class
实体的实例提供到您的域中。
您还提到如果没有Class
,Level
就不能存在。你在这里谈论聚合。关于设计聚合,在线有很多DDD材料。这是一对夫妇:
当一个实体需要另一个实体存在时,它应该始终是一个 聚合
不,仅仅因为实体A依赖于实体B的存在,并不意味着实体A需要属于实体B的聚合。
现在我有一个模型,其中有许多实体(如Class,Level, 主题,顾问,教师等)仅存在于某一学校 (一个实体)。聚合可以获得那么大吗?
此大的聚合可能会导致性能和一致性问题。
Vaughn Vernon在他的三部分Effective Aggregate Design系列中完全涵盖了这些问题。如果您不熟悉DDD术语,这有点令人生畏,但我强烈推荐此阅读!
另外,根据您的说法,实体不应使用存储库。如果 实体中的某些业务逻辑需要数据库访问权限 处理后,应该直接使用DAL吗?
实体不应该对存储库或服务(或其他任何事情)了解任何信息。它们不应该依赖于系统中的任何其他“层”。一切都可以了解您的实体,但您的实体不应该知道其他任何事情。向我提供一个示例,说明为什么您希望实体调用存储库,也许我可以提供更好的答案。