DDD Building Blocks – Value Objects

Value objects are one of the foundational building blocks of Domain-Driven Design. They allow modelling concepts of the Ubiquitous Language that describe, measure or quantify other things in the domain.

It is crucial to understand their characteristics and make more use of them whenever possible instead of trying to model every concept as an Entity or worse, having an Anemic Domain Model where logic related to a value leaks and spreads around services or client code. Values help separating concerns and they are easier to implement, test and maintain.

Examples of Value Objects in a domain could be colour, money, address, e-mail, coordinate, etc. Note that a concept can be an Entity in one domain model and a Value Object in other.

Value Object Characteristics

– Inmutable Conceptual Whole
– Describes, Measures or Quantifies an Entity
– Does not have a unique identity
– Structural equality
– Replaceability
– Side-Effect-Free Behaviour

Implementing Value Objects

Constructors

Value objects are inmutable, do not implement setter methods for its properties, instead provide a constructor with all parameters necessary to initialize its intrinsic state. Parameters may be other objects used to derive internal properties on the new Value.

public class Money {
    private BigDecimal amount;
    private String currency;

    public Money(BigDecimal amount, String currency) {
        this.amount = amount;
        this.currency = currency;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public String getCurrency() {
        return currency;
    }
...

You can find useful, especially for testing immutability, to provide a copy constructor.

    public Money(Money money) {
        this.amount = money.amount;
        this.currency = money.currency;
    }

Use Guard Clauses in the constructor to ensure that the parameters passed are not only valid individually also as a whole initialize a valid Value.

public class FullName {
    private String firstName;
    private String lastName;

    public FullName(String firstName, String lastName) {
        if (firstName == null || lastName == null) {
            throw new IllegalArgumentException("First and last name are required.");
        }

        this.firstName = firstName;
        this.lastName = lastName;
    }
...

Self-encapsulation/delegation

Value objects must not expose setter methods, but internally, we may use and delegate to them to simplify constructors.

Continue reading “DDD Building Blocks – Value Objects”