views:

1514

answers:

4

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 what other scenarios may compel a user to use Monostate instead of Singletons.

+14  A: 

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.

egaga
+1 for linking a *great* article
dfa
Nice paper you linked there. Thank you.
Tobias Langner
Great link! Uncle Bob rules :-)
jens
+15  A: 

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 state of m1
dfa
+1 - Simplistic and exact definition. Nice one.
Kyle Rozendo
+1  A: 

Someone should just note that singletons and monostate are extrememly dangerous patterns. They tend to misused by lazy coders who don't want to have to think about the lifetime of the object they want to make into a singleton. They make testing more difficult and create inflexible systems that are tightly bound.

It's extremely rare to find a situation where a singleton or monostate is genuinely needed. The prefered method of object collaboration is Dependency Injection.

Lots has been written about this:

Ed Sykes
+3  A: 

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.

David Moles
That is pretty neat
Casebash