域驱动设计建议我们应该使用工厂来隐藏复杂性来创建聚合根。我们可以使用以下方法创建聚合根:
在什么基础上我们在(1)和(2)之间进行选择?
答案 0 :(得分:4)
当结果代码与普遍存在的语言更好地对齐,并且当AR具有一些将简化创建过程的知识时,请考虑在AR上使用工厂方法。
例如,如果在您的域中您可以向项目添加任务并且任务被建模为AR,那么Task task = project.addTask(taskId, taskName);
比Task task = new Task(taskId, taskName, projectId);
更具表现力和简单性。
答案 1 :(得分:2)
工厂并不完全专注于DDD。例如,您可以在GoF中找到Factory模式。
通常,您可以根据以下内容做出选择:
说到DDD,你通常会在你的聚合根上使用工厂方法,以封装复杂的创建逻辑,如果你当然有这样的逻辑。工厂根据您的普遍存在的语言命名,并确保只能创建一致的聚合。
答案 2 :(得分:1)
你的第一个建议
你通常应该避免使用工厂类中的静态工厂方法
。如果公共静态方法具有服务特征(工厂可以使用),那么它们就是代码味道。 最好创建一个非静态类,在任何地方注入它并在其上调用实例方法。必要时创建一个接口。这种方法提高了可测试性,并使类之间的依赖关系明确。
如果您遵循此建议,您的问题将成为工厂方法模式与抽象工厂模式的问题。
当有多种方法构造某个类的对象时,请使用工厂方法。在这种情况下,工厂方法比直接构造函数调用更可取,因为您可以为它们提供描述性名称。如果你使用它们,通常使构造函数成为私有的,这样客户就会意识到它们不应该调用构造函数,而是调用适当的工厂方法。
工厂方法只包装构造函数。因此,它们无法真正简化对象的构造(除了给它命名)。
如果构造一个对象非常重要,那么选择的模式就是抽象工厂模式。请注意,您不需要具有多个类,以便能够使用Alexey Zimarev建议的抽象工厂。只使用一种正在创建的对象,抽象工厂才能完美呈现。
抽象工厂是一种特殊的服务,即创建对象的服务。因此,它们可以具有依赖关系,例如,它们可以为创建的对象提供依赖关系。
示例:假设您要创建一个需要字符串值和ISomeService
依赖项的对象。在这里,抽象工厂可以通过提供ISomeService
来提供帮助。工厂的界面将如下所示:
interface IFooFactory {
IBar CreateBar(string value);
}
此工厂简化了为客户创建IBar
的权限,因为他们不必自己提供ISomeService
。
聚合通常包含对域服务的引用。 因此,聚合的实例化通常是非常重要的,因此抽象工厂模式非常适合。
答案 3 :(得分:0)
它们基本相同。选项1.可以帮助您避免使用膨胀的实体类。如果创建在按实体名称加前缀时更自然地读取,则选项2会更好,如
LoyaltyCard.ForCustomer(...)
SavedSearch.WithCriteria(...)