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