【问题标题】:Domain objects - "Smart object" vs POCO域对象 - “智能对象”与 POCO
【发布时间】:2013-07-26 00:46:27
【问题描述】:

通过智能对象,如果属性被更改,我会考虑任何知道其原始属性值的域对象。 智能对象通常有一个基类并通过使用 GetPropertyValue/SetPropertyValue 方法来实现属性。 另一方面,POCO 对象通常没有基类并实现简单的属性。

public class SmartObject : BaseDomainObject
{
    public int id
    {
         get { return (int)this.GetPropertyValue("Id"); }
         set { this.SetPropertyValue("Id", value); }
    }
}

public class POCO
{
    public int id { get; set; }
}

我喜欢智能对象,因为它为我做了很多艰苦的工作。我可以轻松地将所有这些有用的功能添加到 BaseDomainObject 并将它们包含在我所有派生的 Domain 类中:

  • 常用属性(如Id、Status...)
  • 对象状态跟踪(新的、修改的、未更改的)
  • 所有属性都会在属性更改时引发事件(INotifyProperyChanged 的​​实现)
  • 派生类可以自动序列化(虽然我很少发现这很有用)
  • 我可以拥有所有其他有用的行为 - 克隆/同步/IsPropertyDirty...

另一方面,POCO 超级简单,不依赖于任何基类。

现在我在这里得到了很多 POCO 的赞美,因为:

  1. 可以通过网络发送(通常以 JSON 格式发送到 Web 浏览器)
  2. 它是纯粹的

另一方面,我认为上述原因是谬误的,因为:

  1. DTO 用于电汇而不是域对象。将域对象序列化为 JSON 时封装数据的行为。
  2. 这种对纯度的追求与对更虚弱的领域模型的追求相得益彰,它既没有逻辑也没有任何智能。

尽管如此悲伤,我仍然喜欢那个 POCO,它让我很烦。你有什么意见?

【问题讨论】:

  • 如果您正在努力实现丰富的域模型,请不要因技术基础架构问题而污染它。您提到的所有事情——状态跟踪、属性更改事件、序列化——这些事情都与域无关。他们没有将业务领域的复杂性编码到模型中。
  • 另一方面,POCO 也没有将域复杂性编码到模型中。所以按照 DDD 标准,这两种方法都很差。
  • @MattDavey 我同意你的第一条评论,但我不确定后者。 POCO != 贫血,如果这就是你的意思。除了数据之外,普通的旧面向对象确实包括行为,如果适用,还包括域行为。
  • @guillaume31 你是对的。最近似乎 POCO 已成为仅包含 getter/setter 的对象的同义词(导致与 DTO 对象混淆)。我们应该记住POCO的真正含义,您在问题的最后一句话中解释了这一点。

标签: .net architecture domain-driven-design domain-model anemic-domain-model


【解决方案1】:
  • 常用属性(如 Id、Status...)

如果一个对象只是继承了一个定义 Id 属性的实体基类,我不会认为它是非 POCO。根据定义,实体具有身份,不会破坏 SRP,也不会通过导入第三方行为来改变对象的“纯度”。

状态更值得商榷,具体取决于您的意思,它可能确实会在您的对象中引入额外的责任,使其成为非 POCO。

您提到的大多数其他属性我认为应该由外部对象处理,而不是域对象本身。

  • 对象状态跟踪(新的、修改的、未更改的)

最好让域对象的更改跟踪专用代理来处理这个问题(这通常是 ORM 所做的)。

  • 所有属性都会在属性更改时引发事件(INotifyProperyChanged 的​​实现)

我认为大部分与 UI 相关的东西会进入您的演示对象而不是您的域对象。您可能不希望实体中的每个属性都是可观察的 - 要表示聚合中的更改,请改用领域事件。

  • 我可以拥有所有其他有用的行为 - 克隆/同步/IsPropertyDirty...

克隆通常可以是值对象的基本行为,而不会将它们视为非 POCO。除了您偶尔的特定领域需求外,克隆实体对我来说似乎没那么有用。 Sync/IsPropertyDirty 看起来更像是版本控制/更改跟踪,应该委托给专门的对象。

这种对纯度的追求就像对更贫血的领域的追求一样 没有逻辑也没有任何智能的模型。

这里的问题都是关于“附加”的。并不是说符合 SRP 的对象不智能,而是它们不包含任何智能的不是它们的自然责任。同样,POCO 并不愚蠢,它们只是没有移植来自外部资源(3d 方库、框架扩展......)的行为的对象

【讨论】:

  • +1 表示“您可能不希望实体中的每个属性都是可观察的 - 要表示聚合中的更改,请改用领域事件。”
  • 我特别喜欢术语“attached”如何揭示问题本身。
  • 我还认为,通过生成 MSIL,可以轻松地将诸如克隆之类的事情委托给其他组件,而无需更改数据在对象上的存储方式。例如EmitMapper。我也同意对象内部的状态跟踪往往会造成麻烦,但我也不喜欢完全依赖 ORM 状态跟踪,因为它通常需要一些极端的技术。但幸运的是,新对象的 Id 属性为 0。
【解决方案2】:

我会坚持使用 POCO 内部模型,因为那些“智能对象”引入了如此多的复杂性。模型应该尽可能简单,只承载业务逻辑,而不是被可能有用的特性所污染。尤其是技术方面...

【讨论】:

    猜你喜欢
    • 2013-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-27
    • 2012-09-10
    • 2016-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多