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

3 comments:

  1. Dan,

    Just one minor detail; You really do need to declare the class as final for it be immutable.

    Java has been missing good support for properties for soo long now. The JavaBeans pattern with setters / getters does not provide a strong enough conceptual model. I think the separation from methods should be better. Declaring fields as public is one way to go about it, and it works best in combination with final.

    ReplyDelete
  2. Dan,

    Sorry about the anonymous comments. (Google account did not work on the iPad ...)

    Regards,
    Tommy Malmström

    ReplyDelete
  3. Dear Tommy

    You are totally correct. I was mainly thinking about what other parts of the system could do with objects *you* created. And "final String" is good enough for that.

    However, if you want to ensure that all objects of the type Name are immutable, then we must take precaution to ensure that no subclass add functionality that makes the immutable state mutable. As you point out, the most effective way to "seal" the class in this respect is to mark it final, making it impossible to inherit at all.

    Yours

    Dan

    ReplyDelete