Monostate vs. Singleton
Here's what Robert C. Martin has to say about it: Singleton vs. Monostate (pdf)
SINGLETON is best used when you have an existing class that you want to constrain through derivation, and you don’t mind that everyone will have to call the instance() method to gain access. Monostate is best used when you want the singular nature of the class to be transparent to the users, or when you want to employ polymorphic derivatives of the single object.
At its base Monostate is just syntactic sugar around Singleton. Where Monostate gets interesting is when you start subclassing, because the subclasses can decorate the shared state with different behavior.
A simple -- if somewhat contrived and not very efficient :) -- example:
public class GlobalTable implements Iterable<Key> {
/** Shared state -- private */
private static final Map<Key, Value> MAP = new LinkedHashMap<Key, Value>();
/** Public final accessor */
public final Value get(Key key) {
return MAP.get(key);
}
/** Public final accessor */
public final boolean put(Key key, Value value) {
return MAP.put(key);
}
/** Protected final accessor -- subclasses can use this to access
the internal shared state */
protected final Set<Key> keySet() {
return MAP.keySet();
}
/** Virtual -- subclasses can override for different behavior */
public Iterator<Key> iterator() {
return Collections.unmodifiableSet(MAP.keySet()).iterator();
}
}
Now what if we want indexed access?
public class IndexedGlobalTable extends GlobalTable {
public List<Key> getKeysAsList() {
return Collections.unmodifiableList(new ArrayList<Key>(keySet()));
}
public Key getKeyAt(int index) {
return getKeysAsList().get(index);
}
public Value getValueAt(int index) {
return get(getKeyAt(index));
}
}
How about sorted keys?
public class SortedGlobalTable extends GlobalTable {
@Override
public Iterator <Key> iterator() {
return Collections
.unmodifiableSortedSet(new TreeSet<Key>(keySet())).iterator();
}
}
Any time you need one or the other view of the data, you just instantiate the appropriate subclass.
Of course, whether global data is really a good idea in the first place is another question, but at least Monostate gives you more flexibility in how you use it.
monostate and singleton are two faces of the same medal (global state):
- monostate forces a behaviour (only one value along all class instances)
- singleton forces a structural constraint (only one instance)
singleton usage is not transparent
i.e.:
Singleton singleton = Singleton.getInstance();
monostate usage is transparent
i.e.:MonoState m1 = new MonoState();
MonoState m2 = new MonoState(); // same internal state of m1 (e.g. static)