我已经争论了一段时间了,但仍然没有得出结论。虽然我看到的大多数示例在应用程序层中都有工厂代码,但我倾向于认为它应该在域层中。原因:有时我会在我的工厂完成初始验证,我希望所有对象的创建都通过。我希望此代码可用于我的对象的所有实例。有时一个操作需要参数信息,这感觉不自然地传递给构造函数。还有一些不那么重要的原因。
是否有理由说明这是一种不好的做法?这会打破其他模式吗?
我已经争论了一段时间了,但仍然没有得出结论。虽然我看到的大多数示例在应用程序层中都有工厂代码,但我倾向于认为它应该在域层中。原因:有时我会在我的工厂完成初始验证,我希望所有对象的创建都通过。我希望此代码可用于我的对象的所有实例。有时一个操作需要参数信息,这感觉不自然地传递给构造函数。还有一些不那么重要的原因。
是否有理由说明这是一种不好的做法?这会打破其他模式吗?
根据记忆,Eric Evans 的书中有一些示例,其中对象工厂在很大程度上是领域层的一部分。
对我来说,把你的工厂设在这里是非常有意义的。
+1 这样做。可访问性将是一个很好的理由,我会保持创建代码至少接近域模型层。否则,域模型的用户在查找受限访问构造函数时会很困惑如何专门实例化它。实际上,将它分开的一个合理理由是您有不同的有效方法来创建相同的东西,例如,在使用抽象工厂时通常就是这种情况。
如果我不得不将它分开,我会将它放在一个包中(在 Java 的情况下),至少与域模型的级别相同,并始终与它一起发送,例如
upper
--> domain
--> domain_factory
我更喜欢应用层中的工厂。
如果您将工厂保留在域层中,那么当您需要复杂类型作为参数时,它们将无济于事(C# 代码示例):
Application Layer:
//this Factory resides in the Domain Layer and cannot reference anything else outside it
Person person = PersonAggregateFactory.CreateDeepAndLargeAggregate(
string name, string code, string streetName,...
and lots of other parameters...);
//these ones reside in Application Layer, thus can be much more simple and readable:
Person person = PersonAggregateFactory.CreateDeepAndLargeAggregate(CreatePersonCommand);
Person person = PersonAggregateFactory.CreateDeepAndLargeAggregate(PersonDTO);
Domain Layer:
public class Person : Entity<Person>
{
public Address Address {get;private set;}
public Account Account {get;private set;}
public Contact Contact {get;private set;}
public string Name {get;private set;}
public Person(string name, Address address,Account account, Contact contact)
{
//some validations & assigning values...
this.Address = address;
//and so on...
}
}
public class Address:Entity<Address>{
public string Code {get;private set;}
public string StreetName {get;private set;}
public int Number {get;private set;}
public string Complement {get;private set;}
public Address(string code, string streetName, int number, string complement?)
{
//some validations & assigning values...
code = code;
}
}
public class Account:Entity<Account>{
public int Number {get;private set;}
public Account(int number)
{
//some validations & assigning values...
this.Number = number;
}
}
//yout get the idea:
//public class Contact...
此外,没有义务将工厂保持在领域层内(来自领域驱动设计快速):
因此,将创建复杂对象和聚合实例的责任转移到一个单独的对象上,该对象本身在领域模型中可能没有责任,但仍然是领域设计的一部分。提供一个封装所有复杂程序集的接口,并且不需要客户端引用被实例化对象的具体类。将整个聚合创建为一个单元,强制执行它们的不变量。
由于我不使用工厂将持久对象加载到内存中,因此不必从应用程序层之外的其他层访问它们。这就是为什么(来自领域驱动设计快速):
另一个观察结果是工厂需要从头开始创建新对象,或者它们需要重构以前存在但可能已持久化到数据库的对象。将实体从它们在数据库中的静止位置带回内存涉及与创建新实体完全不同的过程。一个明显的区别是新对象不需要新的身份。该对象已经有一个。违反不变量的处理方式不同。从头开始创建新对象时,任何违反不变量的行为都会导致异常。对于从数据库重新创建的对象,我们无法做到这一点。需要以某种方式修复对象,以便它们可以正常工作,否则会丢失数据。
如果建设者/工厂只依赖于领域类和原语,则将它们放在领域层中,否则将它们放在领域层之外。