【问题标题】:Populating your domain objects with data correctly?正确地用数据填充您的域对象?
【发布时间】:2015-07-30 02:10:01
【问题描述】:

我无法理解如何正确设计我的域对象。我一直在努力解决的问题是如何用数据填充我的域对象。我发现的例子对于真正帮助我来说是微不足道的。我尝试了多种方法,但我不喜欢其中任何一种。假设您有大量数据需要传递给您的班级,因此您将其捆绑在 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. 您委托您的客户处理您的数据。似乎不是一个聪明的主意。我相信你最终会遇到变异状态问题。

第三方向(只允许您通过静态工厂方法创建类):

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

【问题讨论】:

  • 自动映射器适合您的情况吗?这样您就可以将数据填充逻辑封装在映射器分析器中或通过 ioc 作为依赖项注入,如果不适合您,我想知道为什么
  • @ming 我不是 100% 明白你在这里得到什么。我从未使用过自动映射器,但我认为我了解基本概念(从一种数据类型转换为另一种数据类型)。这对我有什么帮助?

标签: c# architecture domain-driven-design


【解决方案1】:

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

当我设计一个对象时,我只想到我需要什么输入来实现什么行为。所有对象都应该有一个初始状态,所以你传递一个带有初始值的 DTO(一切都是 POCO,我们不关心这里的持久性)。其实每个方法都是一样的。

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

正如我之前所说,用例作为服务实现,因此在您的场景中,MyClass 实际上是服务,而不是 DO。作为一个经验法则,DO 包含 only 有助于定义对象的数据和行为。 CalculateComplicatedValue 看起来不像是概念的一部分,但它确实看起来像一个用例,因此是一个服务。

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

【讨论】:

  • 哇,我的问题写得真好。这绝对让我思考。我希望我们可以进一步继续这个对话,不幸的是 SO 没有为此设置。所以我看起来我正在走上创建 GOD 对象的道路。我想在某个时候学习 CQRS,但在我考虑走这条路之前,我需要很好地掌握 DDD。
  • @coding4fun 欢迎阅读my articles 了解 DDD 和 CQRS
  • 不幸的是,“我的文章”(blog.sapiensworks.com/topics/#domain-driven-design) 的链接似乎不存在了
猜你喜欢
  • 1970-01-01
  • 2022-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多