Search code examples
design-patternslanguage-agnosticsingleton

Monostate vs. Singleton


What are the scenarios when one would use a Monostate pattern instead of singleton inorder to maintain a global object?

Edit: I know what Singleton and Monostate patterns are. Have also implemented Singleton in quite a few scenarios. Just want to know the scenarios (case examples) where MonoState pattern needs to be implemented.

For eg. I need to maintain list of columns per screen in my windows forms app. I could use a Singleton Dictionary in this case. However, I am storing a List in the static global var and I wanted to provide indexers (since I need to dynamically add new entry to the list if key is not present) where I could specify ScreenDetails.ScreenName as a key & get the ScreenDetails.ColumnsTable. Since indexers can't operate on a static class I changed the pattern to Monostate.

So I would like to know which other scenarios may compel a user to use Monostate instead of Singletons.


Solution

  • 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.