【问题标题】:Actual difference between Value Objects and Entities. DDD值对象和实体之间的实际区别。 DDD
【发布时间】:2023-03-22 05:45:01
【问题描述】:

领域驱动设计,我试图从数学上而不是直观上找出有什么区别。在我当前的项目中,我们在banks 之间进行了某种payment 传输。 在这个系统中,银行不像实体建筑那样被承载,而是抽象的bank。它肯定有BankCode、country 和Bank Name。问题是:Is the bank should be an entity or value object。直觉上觉得应该是实体,但也有人说可以是值对象。

据我所知,entities 可能具有相同的属性但仍然不同。另一方面,value objects 不能有identity,如果所有属性都相同,它们应该相同,它们应该回答它们是什么,而不是它们是谁或它们是谁。如果我错了,请纠正我。

在系统中,banks 在任何流程中都不会发生变化,就像另一个 Value 对象 Country 或 Currency,可能我们可以说,具有相同银行代码、名称和国家的银行是相同的银行.以及我们可以说具有相同国家代码(ISO 格式)的Country 是相同的。但是,对我来说,我仍然觉得它们是实体。有人可以证明我错在哪里,并给出数学证明它们应该是Value 对象或Entities。

目前,我最终得到的是:“The one difference between Entity and Value Object is the entity can contain the all same attributes and still be different, the Value Object can't”,就像交易一样,人们可以拥有相同的金额和商品,相同的姓名,但仍然不同,如果国家、城市和门牌号是一样的。请纠正我,也许还有更多不同之处

【问题讨论】:

  • 非常感谢你们的所有回复,伙计们,它变得更干净了。

标签: domain-driven-design entities value-objects


【解决方案1】:

两者之间的经典示例差异基于上下文(DDD 始终如此),所以让我们继续吧...

经典示例:飞机航班(分配座位或任何座位)...

实体

每个座位都有一个编号,您为乘客分配一个特定座位(座位:10 E)

值对象

飞机有多个座位,您在飞机上为乘客提供 1 个(或多个)座位(不具体,随便坐)。

关键问题是,您关心单个实体(一个席位)还是只关心可用席位的总数?

您可以在此处看到 DDD - 上下文分离,即使您分配座位,也不是每个上下文都会关心。如果我在做容量片,我不关心实体,我只想知道

var unused = available - used.

您最初的问题

简单回答

这是一个实体

深入解答

这取决于上下文。

然后……

在某些情况下,它本身可能是一个领域模型,就像您的上下文一样。

如果我想从 Bank1 和 Bank2 转移资金,我会这样做......


// Both domain models
Bank sendingBank = _bankStore.Get(fromBank.Id);
Bank receivingBank = _bankStore.Get(toBank.Id);

_moneyTransfer(sendingBank, receivingBank, amount);

也可以选择

调用代码

Customer customer = _customerStore.Get(customerId);

var balanace = customer.GetBalance();

实体版本:客户

public class Customer {
    public Bank {get; private set;}

    public Decimal GetBalance () {
       return this.Bank.GetBalance();
    }
}

值对象版本:客户

public class Customer {
   public Balance {get; private set;}

   public Customer (..., decimal bankBalance) {
      this.Balance = bankBalance;
   }
}

【讨论】:

    【解决方案2】:

    银行应该是实体还是价值对象

    先要问的一个问题是:您需要为银行建模吗?

    特别是,您是否控制银行更改的规则?或者您只是管理由其他机构提供给您的信息的本地缓存/存储库(与 ISO 3166 维护机构向我们提供国家代码信息的方式相同)。

    领域驱动设计的一个重要原则是注意确保您正在建模您应该建模的东西。

    我们可以说,具有相同银行代码、名称和国家/地区的银行是同一家银行。以及我们可以说具有相同国家代码(ISO 格式)的 Country 是相同的。但是,对我来说,我觉得它们是实体。

    是的。银行当然是实体。国家也是如此。

    但它们是现实世界的实体。您的域模型不拥有它们。您在数据存储中拥有的是有关这些实体的本地缓存信息。

    例如,ISO-3166-1 标准是一个动态文档;它最近在 2020-03-02 进行了更改(对 MK 全名的更正)。给定的国家代码和日期为您提供了一个固定的标识符。由于国家/地区代码保留 50 年,因此仅国家/地区代码对于重要的时间段是明确的。

    令牌MK 肯定是一个值对象。表示令牌MK 的查找表意味着North Macedonia 是一个实体。但是...它是一个稳定的实体,所以在某些情况下我们可以将其视为固定的。

    (这是标准化标识符的一般属性 - 如果不采用标准,标准将一文不值,因此变更管理政策旨在让采用者更轻松)。

    除非您自己为 ISO 3166/MA 工作,否则它不是您的实体。您拥有的信息只是一个副本。

    我猜你的银行代码也是如此。

    领域驱动设计的部分要点:如果我们努力确保我们真正了解我们试图建模的实际业务问题,那么我们的后续实施将与我们想要的完全一致,并且面对新的需求,很容易改变。

    也就是说,您确实需要确保在您的域上下文中理解“银行”,以确定它是实体还是值对象。

    【讨论】:

    • 感谢您的回复。是的,我们不拥有银行,就像缓存或存储库一样。但是我是否正确理解,这意味着它们是价值对象,那么如果我们从 ISO 等来源获得它们?
    【解决方案3】:

    在您的情况下,bank 应该是一个实体,因为每家银行都有一个唯一的BankCode 来识别它。即使此时您的系统没有更新银行,但这并不意味着将来不可能。

    如果银行的某些属性发生变化,例如,它的主要办公地址(只是编造的......),无论您得到什么变化,唯一标识它的代码将保持不变,因此是同一家银行,但主要办公地址不同。

    这家银行BankCode: 1234, Location: US Texas 和这家银行在Location 属性BankCode: 1234, Location: US Colorado 更改后仍然是同一件事。

    给出数学定义很困难,因为数学是关于值。

    这种唯一性基于不是基于属性,而是基于某种在变化时保持不变的身份,更接近于现实世界是有效的,因此很难给出非直观的定义。

    这是数学中ValueObject 的一个很好的例子。假设您使用向量和矩阵对 3D 数学库进行建模。 Vector 和 Matrix 是 ValueObjects。

    假设我们有两个向量:

    • v1 -> x = 1,y = 2,z = 3
    • v2 -> x = 1,y = 2,z = 3

    您确实有两个向量,但从数学的角度来看,它们是相同的,即表示相同的事物并且相等。这同样适用于矩阵。

    让我们有一个转换 T(例如翻译)。在数学中,您拥有的是:

    v3 = T (v1, v2)

    应用此转换后,您将获得一个全新的向量。我们矢量化的这个品牌可能与 v1 和 v2 具有相同的坐标,因此它们将相等,但您不要更改 v1 或 v2。

    假设您剪了头发,假设这也是一次转型。如果这在现实世界中是真的?

    You2 = T(美发师, You1)

    不,不是。仍然是剪了不同发型的你,当你应用转换时,你不会创造一个不同的你。

    在建模Money 时,根据系统的不同,一个概念既可以是值又可以是实体的一个很好的例子。在您进行银行转账时,您在账户之间转账。在这种情况下,Money 是 ValueObject,因为您不区分 5$ 和 5$,它仍然是相同的金额。

    假设你去商店买饮料,这种饮料是 5 美元。如果您有两个 Banknotes 的 5 美元,那么您使用哪一个来支付并不重要,因为它们代表相同的金额。

    另一方面,每个Banknote 都有一个序列号。这两个 5$ Banknotes 将有不同的序列号,使它们独一无二且不同,因此它们是 Entities。

    如果您的系统跟踪Banknotes,那么您将其建模为Entity。如果不是,则将其建模为ValueObject。

    向量和矩阵上是否有序列号或任何种类的标识?你的车(如果你有的话)可以。如果你去一个有很多汽车的停车场,你有两辆你的车和别人的车,那是完全一样的,你在乎你拿哪一辆吗?好吧,还是拿走你的,否则,它会偷东西,这是违法的,有人会不高兴的。

    让我们再次使用向量和变换 T。

    T(v1, v2)、T(v2, v2) 和 T(v1, v1) 都给出相同的结果,因为这两个向量是相等的,我们不在乎我们使用哪一个。

    【讨论】:

    • 我能理解为什么银行是一个实体,因为银行代码是一样的——银行是一样的。一旦银行代码不同,即使其他属性相同 - 实体也不同。但后来我对 Currency Value 对象感到困惑。情况类似。货币对我来说是价值对象的一个​​原因是它只有货币代码,可以识别每种货币。由于货币没有其他属性可以对于不同的货币是相同的。但银行可能有例如不同银行的银行名称相同,所以是一个实体。我说的对吗?
    • 是的,你是对的,这取决于。为什么?因为这取决于你想从货币中得到什么。如果您只是将货币类型记录为一个值,如果您使用汇率对货币进行建模 - 那么它可能是一个实体。货币类型与货币不同 - 取决于上下文(始终为上下文:D)。
    • @Andriy 我的荣幸。
    猜你喜欢
    • 2010-12-19
    • 2011-03-03
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 2010-10-04
    • 1970-01-01
    • 2014-04-08
    • 2010-11-15
    相关资源
    最近更新 更多