Thursday, June 30, 2011

Defensive copies

One of the building blocks of Domain Driven Design (DDD) is the Value Object: an object that contains attributes but has no conceptual identity. Value Objects should be treated as immutable.

Consider the following class:

public final class Period {
    private final Date start;
    private final Date end;

    public Period(Date start, Date end) {
        this.start = start;
        this.end = end;
    }

    public Date getStart() {
        return start;
    }

    public Date getEnd() {
        return end;
    }
}

This is a common example of the Value Object. What is wrong with this class?

Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
end.setYear(81); //modifies internals of p!

Just because the Period class has no mutator methods it does not mean we can not change its state. In the example above we kept a reference to a mutable object. If we want to prevent this from happening we have to make a defensive copy of each mutable parameter to the constructor:


public Period(Date start, Date end) {
    this.start = new Date(start);
    this.end = new Date(end);
}

Are we there yet? Not really.

Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
p.getEnd().setYear(96); //modifies internals of p!

The common mistake made was exposing a field which is mutable. By returning defensive copies of mutable internal fields our Value Object is finally fixed.

public Date getStart() {
    return new Date(start);
}

public Date getEnd() {
    return new Date(end);
}

Defensive copying can have a performance penalty associated with it. In this particular case my best advice would be to consider Joda-Time's DateTime as an immutable replacement for Date.

In general, you should, where possible, use immutable objects as components of your own objects so that you that don't have to worry about defensive copying. If you do use mutable objects you should think twice before returning a reference to an internal component. Chances are, you should return a defensive copy instead. The same goes for a mutable object entering your internal data structure in the constructor.
If the class trusts its clients and the performance penalty for defensive copying would be too high you may accept or return a reference to a mutable object but be aware - subtle bugs can show up regardless what you wrote in your documentation about your class.

If there is any validation in your constructor it should happen after making the defensive copies in order to eliminate the window of vulnerability between the time the parameters are checked and the time they are copied.


public Period(Date start, Date end) {
    this.start = new Date(start);
    this.end = new Date(end);

    //run validation on this.start and this.end
}

No comments:

Post a Comment