The Power of Value Objects

Although Value Objects are still underestimated players in software design, they may have enormous impact on the quality of your code and flexibility of you domain model. When applied correctly, they increase readability and expressiveness of your code making development and future maintenance much easier. Therefore they should be an elementary tool in every software craftsman’s toolbox.

In this article I want to show:

  • when to use Value Objects
  • how to use Value Objects
  • what are the benefits of using Value Objects

Wrapping primitives

Let’s assume that you have to write a batch tool which takes invoice data stored in DB, makes some complex processing and finally passes processed data to external system. A lot of conditions depend on the invoice status which is defined as INT in the database. According to business requirements, the following rules apply to the invoice status:

Negative status of invoice is not allowed. Invoices with status of 0 to 9 are considered OPEN, and with status greater than 9 are considered CLOSED. Open/Closed classification has impact on processing workflow. Status should be passed to external system in original format (number).

The first approach to modeling could be:

public class Invoice {

    private int status;

    public Invoice(int status, ....) {
        this.status = status;
    }

    public int getStatus() {
        return status;
    }
}

and when we need to use the flag:
Invoice invoice = new Invoice(2, ...);
        ....
        if (invoice.getStatus() < 0) {
            throw new IllegalStateException(
                    "Negative invoice state is not allowed");
        } else if (invoice.getStatus() <= 9) {
            // invoice is OPEN
        } else {
            // invoice closed
        }

This solution has a few drawbacks. It promotes repetitions of code (checking the status value every time we want to use it) and therefore it leads to unmaintainable code. What’s more, each programmer in the team will probably write he’s own status-checking code. It is possible that each version will behave in a bit different way (especially in more complicated cases). How to avoid it? Let’s implement a value object which will wrap the status:
public class InvoiceStatus {

    private int status;

    public InvoiceStatus(int status) {
        if (status < 0) {
            throw new IllegalArgumentException("Negative status not allowed");
        }
        this.status = status;
    }

    public boolean isOpen() {
        return status > 9;
    }

    public boolean isClosed() {
        return !isOpen();
    }

    @Override
    public String toString() {
        return isOpen() ? "OPEN" : "CLOSED";
    }

}

Here we have it all in one place, and anyone who will need to do the “> 9″ check will obviously use the provided method. Furthermore having a dedicated value object makes adding, extending and modifying functionality easier, because the code is not spread over the whole application.

This approach has also one positive side-effect. A method which needs an invoice status as an argument will look like this:

    public void doStuff(InvoiceStatus status) {
        ....
    }

Now you don’t have to worry if someone tries to invoke your method with -123 as an argument. It is guaranteed that you will get a valid invoice status. What’s more, readability increases because you know what to pass as an argument just by looking at the method signature.

Now let’s take a look at a similar example:

public class EmailAddress {

    private final String emailAddress;
    private final String domain;

    public EmailAddress(String email) {
        this.validate(email);

        this.emailAddress = email;
        domain = this.extractDomain(email);
    }

    public boolean isInDomain(String aDomain) {
        return domain.equals(aDomain);
    }

    public String getDomain() {
        return domain;
    }

    public String getEmailAddress() {
        return emailAddress;
    }

    private void validate(String phoneNumberToValidate) {
        // do some regexp, throw runtime exception if needed
    }

    private String extractDomain(String email) {
        // do string manipulation to extract email domain
        return null;
    }

}

Here we have a string data which contains complex information. When we need to extract this information from the String, a wrapping value object seems to be a good solution. Not only does it encapsulate the parsing and string manipulation logic but also takes care about validation.

Arithmetic of Value Objects

Value objects are particularly useful when your domain model includes some kind of arithmetic calculations on money, quantities, measurements etc. In such cases it is extremely useful to define methods which will play the role of operators in expression:

        Money salaryNet = new Money(20000, Money.EUR);
        Money tax = new Money(300, Money.EUR);

        Money salaryGross = salaryNet.plus(tax);

Now let’s imagine that we need to provide calculations for multiple currencies. We can model exchange rate as a smart value object:
    class ExchangeRate {
        private final Currency   sourceCurrency;
        private final Currency   targetCurrency;
        private final BigDecimal rate;

        public ExchangeRate(final Currency sourceCurrency, final Currency targetCurrency, final BigDecimal rate) {
            this.sourceCurrency = sourceCurrency;
            this.targetCurrency = targetCurrency;
            this.rate = rate;
        }

        public Money exchange(final Money money) {
            // do the computations
            return ........;
        }
    }

Now we can use it as follows:
    public Money computeSalaryInUSD() {
        Money salary = new Money(20000, Currency.EUR);
        ExchangeRate eurToUsd = new ExchangeRate(Currency.EUR, Currency.USD, new BigDecimal(1.5));

        return eurToUsd.exchange(salary);
    }

Quite intuitive, isn’t it?

Just like Money was implemented as a pair of amount and unit (currency), also quantities and measurements should be modeled as Whole Values since unit is their fundamental part. But Unit of Measure itself is a good candidate for a Value Object:

class LengthUnit {

        public final static LengthUnit METER     = new LengthUnit("meter", BigDecimal.ONE);
        public final static LengthUnit KILOMETER = new LengthUnit("kilometer", BigDecimal.valueOf(1000));

        private final String           name;
        private final BigDecimal       baseUnitMultiplier;

        public LengthUnit(final String name, final BigDecimal aBaseUnitMultiplier) {
            this.name = name;
            this.baseUnitMultiplier = aBaseUnitMultiplier;
        }

        public BigDecimal findRate(final LengthUnit otherLengthUnit) {
            return this.baseUnitMultiplier.divide(otherLengthUnit.baseUnitMultiplier);
        }

        @Override
        public String toString() {
            return this.name;
        }
    }

Like in example above, we can provide predefined constants to improve usability even more.
Now we can create a full-blown Length model, which is NOT only a number, but a number with it’s unit:
class Length {
        private final BigDecimal quantity;
        private final LengthUnit unit;

        public Length(final BigDecimal quantity, final LengthUnit unit) {
            this.quantity = quantity;
            this.unit = unit;
        }

        public Length to(final LengthUnit targetUnit) {
            return new Length(this.quantity.multiply(this.unit.findRate(targetUnit)), targetUnit);
        }

        @Override
        public String toString() {
            return this.quantity + " " + this.unit;
        }
    }

Note how clear and lucid the code is when we need to use our classes:
        Length hundredMeters = new Length(new BigDecimal(100), LengthUnit.METER);
        Length oneKilometer = new Length(new BigDecimal(1), LengthUnit.KILOMETER);

        System.out.println(hundredMeters.to(LengthUnit.KILOMETER));
        System.out.println(oneKilometer.to(LengthUnit.METER));

We defined our own internal language of objects and operators. Everyone who will come to maintain this code will immediately catch the idea, because this arithmetic of value objects is built based on analogy to the real life. Everyone (at least every software engineer ;) ) learns at school how to add numbers, what are units and what means to convert between different units. Therefore when we need to model it in code, let’s make it explicit.

When to use Value Objects?

I will not even try to make a complete list of cases when Value Objects can be useful, partially because it all depends on the domain you are working in. But basing on examples above I can list a few cases when we should consider the need to create an explicit Object for some implicit concept.

If you are dealing with:

  • primitives with limitations
  • primitives which carry some additional information
  • primitives as arguments and return values in service methods
  • money, time, amounts, units, quantities, measurements

consider introducing explicit Value Object.

Further reading:
Power Use of Value Objects in DDD by Dan Bergh Johnsson
Domain Driven Design by Eric Evans
Alanysis Patterns by Martin Fowler

Follow

Get every new post delivered to your Inbox.