Re: mutate an object or create a new one?
On 2006-10-25 16:10, Oliver Wong wrote:
"Niklas Matthies" <usenet-nospam@nmhq.net> wrote in message
news:slrnejv08e.260l.usenet-nospam@nmhq.net...
I would suggest:
interface Int { int getValue(); }
interface ModifiableInt extends Int { void setValue(int value); }
class ImmutableInt implements Int
{
private final int value;
public ImmutableInt(int value) { this.value = value; }
public int getValue() { return value; }
}
class MutableInt implements ModifiableInt
{
private int value;
public MutableInt(int value) { this.value = value; }
public int getValue() { return value; }
public void setValue(int value) { this.value = value; }
}
2 classes + 2 interfaces? Now that's just being crazy. ;)
You won't have to use them all at the same time. :)
Clients will only "see" either Int, ModifiableInt or (if the guarantee
of immutability really needs to be made explicit) ImmutableInt.
You could also drop MutableInt and instead implement it directly in
ModifiableInt, but this would remove the flexibility of passing a
differently-implemented ModifiableInt to clients. With a simple int
this might not seem so probable, but think of ModifiableList or
similar.
Take the collections framework for example. A better design would have
been to make the Collection interface "unmodifiable" (i.e. with all
the mutating methods removed) and provide a ModifiableCollection
interface that extends it with the mutating methods. Same for List,
Map, Set and so on. Then ArrayList would implement ModifiableList,
but you could still simply pass it to clients as just List and be
certain that they don't modify it (unless they attempt to cast it to
ModifiableList) instead of having to wrap it into an "unmodifiable"
proxy. In addition the framework could provide one ImmutableList class
that implements List and whose constructor takes an arbitrary List
whose elements would be copied to become the contents of the
ImmutableList (which would then be really immutable instead of just
unmodifiable).
To illustrate the analogy with the interfaces/classes above:
Int ~ List
ModifiableInt ~ ModifiableList
ImmutableInt ~ ImmutableList
MutableInt ~ ArrayList, LinkedList, ...
So, yes, it's one additional interface (ModifiableList) and one
additional class (ImmutableList), but it would be much sounder than
the existing design (where you get UnsupportedOperationExceptions),
and it can be used with all List implementations, so it amortizes
pretty well.
Of course, having something like C++'s "const" (or rather its inverse:
a "modifiable" qualifier) would be even better.
-- Niklas Matthies