简体   繁体   English

重视DDD中的对象-为什么不可变?

[英]Value objects in DDD - Why immutable?

I don't get why value objects in DDD should be immutable, nor do I see how this is easily done. 我不明白为什么DDD中的值对象应该是不可变的,也看不到如何轻松地做到这一点。 (I'm focusing on C# and Entity Framework, if that matters.) (如果这很重要,我将专注于C#和Entity Framework。)

For example, let's consider the classic Address value object. 例如,让我们考虑经典的Address值对象。 If you needed to change "123 Main St" to "123 Main Street ", why should I need to construct a whole new object instead of saying myCustomer.Address.AddressLine1 = "123 Main Street"? 如果需要将“ 123 Main St”更改为“ 123 Main Street ”,为什么我需要构造一个全新的对象而不是说myCustomer.Address.AddressLine1 =“ 123 Main Street”? (Even if Entity Framework supported structs, this would still be a problem, wouldn't it?) (即使实体框架支持结构,这仍然是一个问题,不是吗?)

I understand (I think) the idea that value objects don't have an identity and are part of a domain object, but can someone explain why immutability is a Good Thing? 我理解(我认为)值对象没有身份并且是域对象的一部分的想法,但是有人可以解释为什么不变性是一件好事吗?


EDIT : My final question here really should be "Can someone explain why immutability is a Good Thing as applied to Value Objects ?" 编辑 :我在这里的最后一个问题确实应该是“有人可以解释为什么不变性是应用于Value Object的一件好事吗?” Sorry for the confusion! 对困惑感到抱歉!


EDIT : To clairfy, I am not asking about CLR value types (vs reference types). 编辑 :为了聪明,我不是在问CLR值类型(相对于引用类型)。 I'm asking about the higher level DDD concept of Value Objects. 我问的是价值对象的更高层次的DDD概念。

For example, here is a hack-ish way to implement immutable value types for Entity Framework: http://rogeralsing.com/2009/05/21/entity-framework-4-immutable-value-objects . 例如,这是一种为实体框架实现不可变值类型的方法: http : //rogeralsing.com/2009/05/21/entity-framework-4-immutable-value-objects Basically, he just makes all setters private. 基本上,他只是将所有二传手设为私人。 Why go through the trouble of doing this? 为什么要麻烦这样做呢?

Ignore all the crazy answers about thread safe etc, that has nothing to do with DDD. 忽略所有与线程安全等有关的疯狂答案,这些答案与DDD无关。 (I've yet to see a thread safe O/R mapper or other DDD friendly dal) (我尚未看到线程安全的O / R映射器或其他DDD友好的dal)

Imagine a value object for weights. 想象一下一个权重的值对象。 lets say we have a KG value object. 假设我们有一个KG值对象。

sample (edited for clarity): 样本(为清楚起见进行了编辑):

var kg75 = new Weight(75);
joe.Weight = kg75;
jimmy.Weight = kg75;

Now what would happen if we do: 现在,如果我们这样做会发生什么:

jimmy.Weight.Value = 82;

That would change the weight of joe too, if we are still using the same object references that is. 如果我们仍然使用相同的对象引用,那也将改变joe的权重。 Note that we assigned an object representing 75kg to both joe and jimmy. 请注意,我们为joe和jimmy分配了一个代表75kg的对象。 When jimmy gains weight, it is not the kg75 object that has changed, it is jimmys weight that has changed, thus, we should create a new object representing 82 kg. 当jimmy变胖时,不是kg75对象发生了变化,而是jimmys体重发生了变化,因此,我们应该创建一个代表82 kg的新对象。

But what if we have a new session and load both joe and jimmy in a clean UoW? 但是,如果我们有一个新会话并在干净的UoW中加载joe和jimmy,该怎么办?

 var joe = context.People.Where(p => p.Name = "joe").First();
 var jimmy = context.People.Where(p => p.Name = "jimmy").First();
 jimmy.Weight.Value = 82;

What would happen then? 那会发生什么呢? well, since EF4 in your case would load joe and jimmy and their weights without any identity , we would get two different weight objects and when we change jimmys weight , joe would still weigh the same as before. 好吧,由于在您的情况下EF4会加载joe和jimmy以及它们的重量而没有任何标识,因此我们将得到两个不同的重量对象,并且当我们更改jimmys的重量时,joe的重量仍与以前相同。

So we would have two different behaviours for the same code. 因此,对于同一代码,我们将有两种不同的行为。 If the object references are still the same, then both joe and jimmy would get a new weight. 如果对象引用仍然相同,则joe和jimmy都将获得新的权重。 If joe and jimmy are loaded in a clean uow, only one of them would be affected by the change. 如果将joe和jimmy放在干净的床单中,则只有其中一个会受到更改的影响。

And that would be quite incosistent imo. 那将是相当令人讨厌的imo。

By using immutable VO's, you would get the same behavior in both cases and you can still reuse object references for a smaller memory footprint when constructing object graphs. 通过使用不可变的VO,在两种情况下您将获得相同的行为,并且在构造对象图时仍可以将对象引用重用于较小的内存。

Why is 6 immutable? 为什么6是不变的?

Understand that, and you will understand why Value Objects should be immutable. 理解这一点,您将理解为什么值对象应该是不变的。

Edit: I'll lift our dialog into this answer now. 编辑:我现在将我们的对话框放入这个答案。

6 is immutable because 6 's identity is determined by what it represents, namely the state of having six of something. 6是不可变的,因为6的身份取决于它所代表的内容,即拥有六个东西的状态。 You can't change that 6 represents that. 您不能更改6代表的数字。 Now, this is the fundamental concept of Value Objects. 现在,这是价值对象的基本概念。 Their value is determined by their state. 他们的价值取决于他们的状态。 An Entity, however, is not determined by its state. 但是,实体不是由其状态决定的。 A Customer can change their last name, or their address and still be the same Customer . Customer可以更改其姓氏或地址,并且仍然是同一Customer This is why Value Objects should be immutable. 这就是为什么值对象应该是不可变的。 Their state determines their identity; 他们的状态决定了他们的身份; if their states changes, their identity should change. 如果他们的状态改变了,他们的身份也应该改变。

I'm very late to the party, but I'd been wondering about this myself. 我参加聚会很晚,但是我自己一直对此感到疑惑。 (Would appreciate any comments.) (不胜感激。)

I don't think it's been explicitly quoted here, but I think Evans' references to immutability were primarily in the context of sharing: 我认为这里没有明确引用,但我认为Evans提到不变性主要是在共享的背景下:

in order for an object to be shared safely , it must be immutable: it cannot be changed except by full replacement. 为了安全地共享对象 ,它必须是不可变的:除非进行完全替换,否则不能更改。 (Evans p100) (埃文斯p100)

There's also a sidebar in Evan's book called "Is Address a Value Object? Who's asking?". 埃文(Evan)的书中还有一个侧栏,名为“地址是值对象吗?谁在问?”。

If roommates each called to order electrical service [ie if two customers had the same address], the company would need to realize it. 如果每个室友都要求订购电气服务(即,如果两个客户的地址相同),则公司需要实现这一点。 [So] Address is an Entity. [所以]地址是一个实体。 (Evans p98) (埃文斯p98)

In the example you gave, suppose the customer's Home and Business Address were both 123 Main Street. 在您给出的示例中,假设客户的家庭住址和公司地址均为Main Street 123。 When you make the correction you describe, would both addresses change? 当您描述更正时,两个地址都会更改吗? If so, and if I'm reading Evans correctly, it sounds like you really have an Entity. 如果是这样,并且如果我正确阅读了Evans,则听起来您确实拥有一个实体。

Taking a different example, suppose we had an object to represent a customer's full name: 再举一个例子,假设我们有一个对象来代表客户的全名:

public class FullName
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Customer
{
    public FullName Name { get; set; }
}

Without a value object, the following would fail: 没有值对象,以下操作将失败:

[Test]
public void SomeTest() {
    var fullname = new FullName { FirstName = "Alice", LastName = "Jones" };
    var customer1 = new Customer { Name = fullname };
    var customer2 = new Customer { Name = fullname };

    // Customer 1 gets married.
    customer1.Name.LastName = "Smith";

    // Presumably Customer 2 shouldn't get their name changed.
    // However the following will fail.
    Assert.AreEqual("Jones", customer2.Name.LastName);
}

In terms of advantages generally, some are picked up at In DDD, what are the actual advantages of value objects? 就优势而言,通常在DDD中有一些优势,价值对象的实际优势是什么? . Notably, you only have to validate a VO on creation. 值得注意的是,您只需要在创建时验证VO。 If you do that, then you know it's always valid. 如果这样做,那么您就会知道它始终有效。

This might not be the complete answer. 这可能不是完整的答案。 I am only answering your question on the advantages of Immutability. 我只是在回答您关于不变性优点的问题。

  1. Because Immutable objects are thread safe. 因为不可变对象是线程安全的。 Since they cannot change state, they cannot be corrupted by thread interference or observed in an inconsistent state. 由于它们不能更改状态,因此它们不能被线程干扰破坏或在不一致的状态下观察到。
  2. The references to the immutable objects can be easily shared or cached without having to copy or clone them as their state can not be changed ever after construction. 对不可变对象的引用可以轻松地共享或缓存,而不必复制或克隆它们,因为在构造之后就无法更改它们的状态。
  3. For more advantages of Immutability you look here (LBushkin's answer) What's the advantage of a String being Immutable? 有关不可变性的更多优点,请看此处(LBushkin的答案) :字符串不可变的优点是什么?

This is an example by Martin Fowler on why value objects should be Immutable. 这是马丁·福勒(Martin Fowler )的一个例子 ,说明为什么值对象应该是不可变的。

Alright, while it is not mandatory to make VO as immutable (even DDD book doesn't say they have to be immutable), the main idea, in DDD, to make it a VO seems to be not to deal with life cycle complexities like that of an Entity. 好吧,虽然不一定要使VO不可变(即使DDD书也没有说它们必须是不可变的),但在DDD中使其变为VO的主要思想似乎并不是在处理诸如生命周期之类的复杂性实体的。 Look here for more details . 在这里查看更多详细信息

Value objects need to be immutable. 值对象必须是不可变的。

Immutable objects do indeed make life simpler in many cases. 在许多情况下,不可变的对象确实确实使生活变得更简单。 ... And they can make concurrent programming way safer and cleaner for more info ...并且它们可以使并发编程方式更安全,更清洁, 以获取更多信息

Let's consider value object to be mutable. 让我们考虑值对象是可变的。

class Name{
string firstName,middleName,lastName
....
setters/getters
}

Let's say your original Name was Richard Thomas Cook 假设您的原名是Richard Thomas Cook

Now let's say you change only the firstName(to Martin) and lastName(to Bond), If it's not an immutable object, you will use the methods to mutate the state one by one. 现在,假设您仅将firstName(更改为Martin)和lastName(更改为Bond),如果它不是不可变的对象,则将使用这些方法逐一更改状态。 Chances of having name as Martin Thomas Cook in that Aggregate state before the final name of Martin Thomas Bond is never acceptable(also it gives a wrong thinking to the one who looks code later,leading to undesirable dominoes effect in further design). 马丁·托马斯·邦德Martin Thomas Bond )的最终名称之前的那个聚合状态中,有可能将名字命名为马丁·托马斯· 库克Martin Thomas Cook) ,这是永远不可能的(这也给后来看代码的人带来了错误的想法,从而在进一步的设计中导致不良的多米诺效应)。

Mutable value objects explicitly have to enforce integrity constraints for the changes given in 1 transaction,which is given free in Immutable objects. 可变值对象显式地必须对1个事务中给定的更改强制执行完整性约束,这在不可变对象中是免费提供的。 Hence it makes sense to make value objects immutable. 因此,使价值对象不变是有意义的。

This has been asked a long time ago but I've decided to provide an answer with an example which I find straightforward and very simple to remember. 这是很久以前问过的,但我决定提供一个示例,我觉得它很简单也很容易记住。 Besides, SO works as a reference for many developers and I think anyone who bumps into this question could benefit from it. 此外,SO为许多开发人员提供了参考,我认为任何遇到此问题的人都可以从中受益。

Because they are defined by their attributes, value objects are treated as immutable . 因为它们是由属性定义的,所以值对象被视为不可变的

A good example of a value object is money. 价值对象的一个​​很好的例子是金钱。 It doesn't matter that you can't distinguish between the same five one dollar bills in your pocket. 没关系,您也无法在口袋中分辨出相同的五张一美元钞票。 You don't care about the currency's identity -only about its value and what it represents. 您不在乎该货币的身份,仅在乎其价值及其代表什么。 If somebody swapped a five dollar bill for one you have in your wallet, it would not change the fact that you still have five dollars. 如果有人用一张五美元的钞票换成你钱包里的那张钞票,那不会改变你仍然有五美元的事实。

So, for example, in C#, you define money as a immutable value object: 因此,例如,在C#中,您将金钱定义为不可变值对象:

public class Money
{
    protected readonly decimal Value;

    public Money(decimal value)
    {
        Value = value;
    }

    public Money Add(Money money)
    {
        return new Money(Value + money.Value);
    }

    // ...


    // Equality (operators, Equals etc) overrides (here or in a Value Object Base class). 
    // For example:

    public override bool Equals(object obj)
    {
        return Equals(obj as Money);
    }

    public bool Equals(Money money)
    {
        if (money == null) return false;
        return money.Value == Value;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM