What is a Value Object?
In Domain-Driven Design (DDD), Value Objects represent concepts or attributes that don’t have their own identity but are defined by their attributes. These objects are immutable, meaning their state cannot be changed once they are created. Value Objects are distinguished from Entities, which have their own identity.
Characteristics of Value Objects:
- Immutability: Once a Value Object is created, its state cannot be changed. This ensures that its value remains consistent and predictable.
- Equality by Value: Value Objects are compared based on the equality of their attributes rather than their identity. If two Value Objects have the same attributes, they are considered equal, regardless of whether they are the same instance.
- Side-Effect Free: Value Objects do not perform any side effects. They are pure functions of their attributes.
Example: Let’s understand with an example in C#. EmailAddress Value Object
using System;
public class EmailAddress : IEquatable
{
private readonly string _value;
public EmailAddress(string value)
{
if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("Email address cannot be empty.", nameof(value));
_value = value;
}
public bool Equals(EmailAddress other)
{
if (other is null) return false;
if (ReferenceEquals(this, other)) return true;
return _value == other._value;
}
public override bool Equals(object obj)
{
return Equals(obj as EmailAddress);
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public override string ToString()
{
return _value;
}
}
class Program
{
static void Main(string[] args)
{
try
{
var email1 = new EmailAddress("user@example.com");
var email2 = new EmailAddress("user@example.com");
var email3 = new EmailAddress("anotheruser@example.com");
Console.WriteLine($"Email 1: {email1}");
Console.WriteLine($"Email 2: {email2}");
Console.WriteLine($"Email 3: {email3}");
Console.WriteLine($"Is email1 equal to email2? {email1.Equals(email2)}");
Console.WriteLine($"Is email1 equal to email3? {email1.Equals(email3)}");
}
catch (ArgumentException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
Explanation:
- We define the EmailAddress class as a Value Object representing an email address.
- The constructor ensures that the email address provided is not null or empty.
- We override the Equals method to compare email addresses based on their string value.
- In the Main method, we create three instances of EmailAddress representing different email addresses.
- We print out the email addresses and check for equality between them.