Friday, 9 September 2011

"public final" is also Immutable

Dear Junior

Immutable value objects are one of my favourite programming idioms. I really like how they aid and ease the burden of the rest of the code by taking care of small pieces of complexity. When they are based on the concepts of the domain they become yet another magnitude more valuable. 

Implementation-wise they are most often a primitive type wrapped up in a protecting box. So it is pretty natural that a "name" is stored with a String containing the full name. Wrapped together in the box is probably as well some complexity, like the validation of the name and some interpretations of the data - in this case the logic to split a full name into its parts. At the end of the day, it is not so interesting to encapsulate the data as such - it is encapsulating the interpretation of the data that is crucial. In Java such a name class would look like this.

public class Name {
    public final String fullname;

    public Name(String fullname) {
        if(!fullname.matches("[a-zA-Z\\ ]+"))
            throw new IllegalArgumentException();
        this.fullname = fullname;
    }

    public String[] names() {
        return fullname.split(" ");
    }
}

Now, one thing worth noting is the datafield "fullname". It plays double roles both as data storage and as an attribute. Should we not have a private field and an accessor method instead?

Well, the integrity of the object is still guaranteed as

  • the datafield is final so the referred object cannot be exchanged 
  • the referred object (String) is immutable so the referred object cannot be changed 

So, yes, people can get to the field from the outside, but they cannot break anything. Of course there is the question that if you change the data representation, then you will break the clients.

However, that is no big deal. If the situation should arise, we can apply the refactoring "encapsulate field" to introduce a new method "String fullname()" and replace every access to the field with a call to that method instead. Checking the entire codebase for accesses to "fullname" might be a large task. But, guess what, using a modern IDE there will be a menu item in the "Refactoring" menu that will do exactly that - fully automated.

The alternative would be to have that code in from the start. However, I cannot see that there is a point in paying the overhead of more lines of code in the meantime.

Making a field public does not break encapsulation. The important encapsulation is the interpretation and constraints of the data that is found in the constructor validation and the logic of the method "names()".

By the way: in Scala you would not be able to see the difference between a public field and a method with the same name. Nice.

Yours
   Dan