使用数据正确填充域对象?
Populating your domain objects with data correctly?
我无法理解如何正确设计我的域对象。我一直在努力解决的问题是如何用数据填充我的域对象。我发现的例子对于真正帮助我来说是微不足道的。我尝试了多种方法,但我都不喜欢其中任何一种。假设您有大量数据需要传递到 class 中,因此您将其捆绑在 POCO 中。
我的第一个方向(将数据传入构造函数):
public class MyClass
{
private readonly ICalculator _calculator;
private readonly MyClassDataPOCO _data;
public MyClass(ICalculator _calculator, MyClassDataPOCO data)
{
this._calculator = _calculator;
_data = data
这不是很好,因为你的 IOC 容器不能自动初始化你的 classes。
第二个方向(将数据传递到操作中):
public class MyClass
{
private readonly ICalculator _calculator;
public MyClass(ICalculator _calculator)
{
this._calculator = _calculator;
}
public decimal CalculateComplicatedValue1(MyClassDataPOCO data)
{
}
public decimal CalculateComplicatedValue2(MyClassDataPOCO data)
{
}
出于各种原因我不喜欢这个
- 您的 class 只不过是实例函数(不是真正的 classes)。他们只有行为,没有数据。
- 您将数据委托给您的客户。似乎不是一个聪明的主意。我相信你最终会 运行 陷入变异状态问题。
Third Direction(只允许你class通过静态工厂方法创建):
public class MyClass
{
private readonly ICalculator _calculator;
private MyClassDataPOCO _data;
private MyClass(ICalculator _calculator)
{
this._calculator = _calculator;
}
public static MyClass Create(MyClassDataPOCO data)
{
return Create(_container.GetInstance<ICalculator>(), data);
}
public static MyClass Create(ICalculator calculator, MyClassDataPOCO data)
{
//do some input validation here
var myReturn = new MyClass(calculator);
myReturn._data = data;
return myReturn;
}
我想在所有选项中我最喜欢这个。我唯一不喜欢的是必须有两个创建函数,所以它可以进行单元测试(所以我可以注入 ICalculator)。
我没有尝试的唯一选择是 属性 注入,因为 id 认为通过属性注入数据不是一个好主意。
您根据业务概念和用例设计域对象 (DO)。根据我的经验,这意味着您的对象应该非常纤细。 DO是基于概念定义来实现的。业务用例在服务中实现(可以是应用程序服务,可以是域服务,这取决于上下文),它将使用 DO 来更新内容。
当我设计一个对象时,我只是想我需要什么样的输入来实现什么样的行为。所有对象都应具有初始状态,因此您可以传递具有初始值的 DTO(一切都是 POCO,我们不关心这里的持久性)。其实每个方法都是一样的
关于持久性,因为我使用的是 CQRS,所以我只关心 save/get 一个对象。我个人更喜欢 json 对象(如果我不使用事件源),所以 save=serialize,get=deserialize。关于封装,您可以将 json 序列化程序配置为使用私有属性,基本上拥有私有属性是您做出的唯一妥协。
正如我之前所说,用例是作为服务实现的,因此在您的场景中,MyClass
实际上是服务,而不是 DO。作为经验法则,DO 包含 仅 有助于定义对象的数据和行为。 CalculateComplicatedValue
看起来不像概念的一部分,但它看起来确实像一个用例,因此是一项服务。
这里不需要工厂,实例化 DO 通常很简单,但是服务通常由 DI 容器实例化,因为在大多数情况下服务确实使用其他服务(如存储库或验证器) .
我无法理解如何正确设计我的域对象。我一直在努力解决的问题是如何用数据填充我的域对象。我发现的例子对于真正帮助我来说是微不足道的。我尝试了多种方法,但我都不喜欢其中任何一种。假设您有大量数据需要传递到 class 中,因此您将其捆绑在 POCO 中。
我的第一个方向(将数据传入构造函数):
public class MyClass
{
private readonly ICalculator _calculator;
private readonly MyClassDataPOCO _data;
public MyClass(ICalculator _calculator, MyClassDataPOCO data)
{
this._calculator = _calculator;
_data = data
这不是很好,因为你的 IOC 容器不能自动初始化你的 classes。
第二个方向(将数据传递到操作中):
public class MyClass
{
private readonly ICalculator _calculator;
public MyClass(ICalculator _calculator)
{
this._calculator = _calculator;
}
public decimal CalculateComplicatedValue1(MyClassDataPOCO data)
{
}
public decimal CalculateComplicatedValue2(MyClassDataPOCO data)
{
}
出于各种原因我不喜欢这个
- 您的 class 只不过是实例函数(不是真正的 classes)。他们只有行为,没有数据。
- 您将数据委托给您的客户。似乎不是一个聪明的主意。我相信你最终会 运行 陷入变异状态问题。
Third Direction(只允许你class通过静态工厂方法创建):
public class MyClass
{
private readonly ICalculator _calculator;
private MyClassDataPOCO _data;
private MyClass(ICalculator _calculator)
{
this._calculator = _calculator;
}
public static MyClass Create(MyClassDataPOCO data)
{
return Create(_container.GetInstance<ICalculator>(), data);
}
public static MyClass Create(ICalculator calculator, MyClassDataPOCO data)
{
//do some input validation here
var myReturn = new MyClass(calculator);
myReturn._data = data;
return myReturn;
}
我想在所有选项中我最喜欢这个。我唯一不喜欢的是必须有两个创建函数,所以它可以进行单元测试(所以我可以注入 ICalculator)。
我没有尝试的唯一选择是 属性 注入,因为 id 认为通过属性注入数据不是一个好主意。
您根据业务概念和用例设计域对象 (DO)。根据我的经验,这意味着您的对象应该非常纤细。 DO是基于概念定义来实现的。业务用例在服务中实现(可以是应用程序服务,可以是域服务,这取决于上下文),它将使用 DO 来更新内容。
当我设计一个对象时,我只是想我需要什么样的输入来实现什么样的行为。所有对象都应具有初始状态,因此您可以传递具有初始值的 DTO(一切都是 POCO,我们不关心这里的持久性)。其实每个方法都是一样的
关于持久性,因为我使用的是 CQRS,所以我只关心 save/get 一个对象。我个人更喜欢 json 对象(如果我不使用事件源),所以 save=serialize,get=deserialize。关于封装,您可以将 json 序列化程序配置为使用私有属性,基本上拥有私有属性是您做出的唯一妥协。
正如我之前所说,用例是作为服务实现的,因此在您的场景中,MyClass
实际上是服务,而不是 DO。作为经验法则,DO 包含 仅 有助于定义对象的数据和行为。 CalculateComplicatedValue
看起来不像概念的一部分,但它看起来确实像一个用例,因此是一项服务。
这里不需要工厂,实例化 DO 通常很简单,但是服务通常由 DI 容器实例化,因为在大多数情况下服务确实使用其他服务(如存储库或验证器) .