Question

I want to have immutable Java objects like this (strongly simplified):

class Immutable {

    protected String name;

    public Immutable(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

In some cases the object should not only be readable but mutable, so I could add mutability through inheritance:

public class Mutable extends Immutable {

    public Mutable(String name) {
        super(name);
    }

    public void setName(String name) {
        super.name = name;
    }

}

While this is technically fine, I wonder if it conforms with OOP and inheritance that mutable is also of type immutable. I want to avoid the OOP crime to throw UnsupportedOperationException for immutable object, like the Java collections API does.

What do you think? Any other ideas?

Was it helpful?

Solution

Avoid calling the parent "Immutable" because it becomes a lie in the child class - if you do want to make a class immutable, it should be final too in order to prevent exactly this problem.

Joda Time uses "ReadableXXX" to give the idea that "this class only provides read access; other subclasses may be mutable". I'm not sure whether I like that idea, but I can't say I've seen many alternatives.

Basically the problem is with expressing a negative - Immutable describes what you can't do (mutate it) and that can't be sensibly enforced in subclasses. (Even if the fields within Immutable were final, it wouldn't stop a subclass having its own mutable fields.)

OTHER TIPS

I would suggest that you should have an inheritable base "ReadableFoo" class, a derived sealed ImmutableFoo class, and other derived MutableFoo classes. Code which doesn't care whether a Foo is mutable or not can accept a ReadableFoo. Code that wants a Foo that is guaranteed not to change can accept an ImmutableFoo. Code which can need to change a Foo can accept a MutableFoo.

Note that the constructors for both ImmutableFoo and MutableFoo should typically accept a ReadableFoo. That way, any Foo will be convertible to a mutable or immutable version.

Immutable classes should be final precisely to avoid mutable sub-types.

Allowing a sub-type of an immutable class to break the immutable contract makes it rather pointless to have the class be immutable in the first place. It may be legal in the sense that Java allows you to do it (immutability is not enforced in the language) but such a class isn't truly immutable as long as it can be sub-classed.

This is why String is final.

Your subclass is bad because it violates the Liskov substitution principle. Don't do it.

I find your code rather curious.

To implement such an Immutable behaviour, I would rather has relied upon an Immutable interface, providing only the getter method, whiile the object contains both. This way, operations relying on the immutable objects would have called the interface, while others would have called the object.

And, if you really don't want your immutable objects to be casted as mutable ones, you can then use proxies, and all the enterprise tools (aspects, and so on). But usually, relying upon other developpers' goodwill is a sweet way to make them responsible of their mistakes (like casting the immutable in mutable).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top