Wednesday, August 3, 2022

Value Object

One of the domain modeling building blocks is a value object. Value objects are an entity's state, describing something about the entity or the things it owns.

Value objects are always preferred over entities because they are immutable and lightweight. Due this reason, it is easy to work with them.

In the .NET world, records are good candidates to implement value objects. Below, you can see how a value object can look implemented in C#.


public record Money
{
    public decimal Amount { get; init; }

    public Money(decimal amount)
    {
        if (amount % 0.01m != 0)
        {
            throw new ArgumentException("More than two decimal places", nameof(amount));
        }

        Amount = amount;
    }

    public Money Add(Money value)
    {
        return new Money(Amount + value.Amount);
    }

    public Money Substract(Money value)
    {
        return new Money(Amount - value.Amount);
    }
}

Characteristics

Every value object has to match such characteristics:

  • Identity-Less
  • Attribute-Based Equality
  • Immutable
  • Behavior-Rich
  • Self-Validating

Now let's dive deep into each value objects characteristics. 

Identity-Less

Value objects have no identity.

Attribute-Based Equality

Value objects are considered equal if they have the same value.

var a = new Money(10M);
var b = new Money(10M);
Console.WriteLine(a == b); // True

Immutable

Once created, a value object can not be changed.

var a = new Money(10M);
a.Amount = 12M; // Can't be assigned

Behavior‐Rich

As much as possible, value objects should expose expressive domain‐oriented behavior and encapsulate the state.

var a = new Money(10M);
var b = a.Substract(new Money(2M));
Console.WriteLine(b); // Money { Amount = 8 }

Self‐Validating

Value objects should never be in an invalid state.

var a = new Money(10.0348M); // Throws exception "More than two decimal places"

No comments:

Post a Comment