使用正确的数据填充域对象?

时间:2015-07-29 15:54:55

标签: c# architecture domain-driven-design

我无法理解如何正确设计我的域对象。我一直在努力解决的问题是如何用数据填充我的域对象。我发现的例子对于真正帮助我来说是微不足道的。我尝试了各种各样的方法,但我不喜欢它们中的任何一种。假设您需要将大量数据传递到类中,以便将其捆绑在POCO中。

我的第一个方向(将数据传递给构造函数):

public class MyClass
{
    private readonly ICalculator _calculator;
    private readonly MyClassDataPOCO _data;

    public MyClass(ICalculator _calculator, MyClassDataPOCO data)
    {
        this._calculator = _calculator;
        _data = data

这不好用,因为那时你的IOC容器不能自动初始化你的类。

第二个方向(将数据传递到操作中):

public class MyClass
{
    private readonly ICalculator _calculator;

    public MyClass(ICalculator _calculator)
    {
        this._calculator = _calculator;
    }

    public decimal CalculateComplicatedValue1(MyClassDataPOCO data)
    {

    }

    public decimal CalculateComplicatedValue2(MyClassDataPOCO data)
    {

    }

我出于各种原因不喜欢这个

  1. 你的课程只不过是实例函数(不是真正的类)。他们只有行为而不是数据。
  2. 您委托客户处理您的数据。看起来不是一个聪明的主意。我相信你最终会遇到变异的状态问题。
  3. 第三方向(仅允许您通过静态工厂方法创建课程):

    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不认为通过属性注入数据是个好主意。

1 个答案:

答案 0 :(得分:2)

您根据业务概念和用例设计域对象(DO)。根据我的经验,这意味着你的物体应该非常纤细。 DO基于概念定义实现。业务用例在服务中实现(可以是应用服务,可以是域服务,它取决于上下文),它将使用DO来更新内容。

当我设计一个对象时,我只想到我需要什么样的行为。所有对象都应该具有初始状态,因此您使用初始值传递DTO(一切都是POCO,我们不关心这里的持久性)。实际上,每种方法都是一样的。

关于持久性,因为我使用CQRS,我只关心保存/获取对象。我个人更喜欢json这个对象(如果我不使用事件源)所以save = serialize,get = deserialize。关于封装,您可以将json序列化程序配置为使用私有属性,并且基本上具有私有属性是您唯一的妥协。

正如我之前所说的,用例是作为服务实现的,因此在您的方案中,MyClass实际上是服务,而不是DO。作为拇指规则,DO包含数据和行为,这有助于定义对象。 CalculateComplicatedValue看起来不像概念的一部分,但它看起来像一个用例,因此就是一种服务。

您在这里不需要工厂,实例化DO通常很简单,但是服务通常由DI容器实例化,因为在大多数情况下服务确实使用其他服务(如存储库或验证器)