Monostate vs. Singleton

Design PatternsLanguage AgnosticSingleton

Design Patterns Problem Overview


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.

Design Patterns Solutions


Solution 1 - Design Patterns

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)  

Solution 2 - Design Patterns

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.

Solution 3 - Design Patterns

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.

Solution 4 - Design Patterns

Someone should just note that singletons and monostates are extremely dangerous patterns. They tend to get 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:

Solution 5 - Design Patterns

The difference between the two patterns is one of behavior vs. structure. The SINGLETON pattern enforces the structure of singularity. It prevents any more than one instance from being created. Whereas MONOSTATE enforces the behavior of singularity without imposing structural constraints.

Benefits of the SINGLETON

  • Applicable to any class. You can change any class into a SINGLETON simply by making its constructors private and by adding the appropriate static functions and variable.
  • Can be created through derivation. Given a class, you can create a subclass that is a SINGLETON.
  • Lazy evaluation. If the SINGLETON is never used, it is never created.

Costs of the SINGLETON

  • Destruction is undefined. There is no good way to destroy or decommission a SINGLETON. If you add a decommission method that nulls out the instance, other modules in the system may still be holding a reference to the SINGLETON instance. Subsequent calls to Instance will cause another instance to be created, causing two concurrent instances to exist.

  • Not inherited. A class derived from a SINGLETON is not a singleton. If it needs to be a SINGLETON, the static function, and variable need to be added to it.

  • Efficiency. Each call to Instance invokes the if statement. For most of those calls, the if statement is useless.

  • Nontransparent. Users of a SINGLETON know that they are using a SINGLETON because they must invoke the Instance method.

Benefits of MONOSTATE

  • Transparency. Users of a MONOSTATE do not behave differently than users of a regular object. The users do not need to know that the object is MONOSTATE.

  • Derivability. Derivatives of a MONOSTATE are MONOSTATES. Indeed, all the derivatives of a MONOSTATE are part of the same MONOSTATE. They all share the same static variables.

  • Polymorphism. Since the methods of a MONOSTATE are not static, they can be overridden in a derivative. Thus different derivatives can offer different behavior over the same set of static variables.

  • Well-defined creation and destruction. The variables of a MONOSTATE, being static, have well-defined creation and destruction times.

Costs of MONOSTATE

  • No conversion. A normal class cannot be converted into a MONOSTATE class through derivation.

  • Efficiency. A MONOSTATE may go through many creations and destructions because it is a real object. These operations are often costly.

  • Presence. The variables of a MONOSTATE take up space, even if the MONOSTATE is never used.

Agile Software Development, Principles, Patterns, and Practices Robert C. Martin

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSO UserView Question on Stackoverflow
Solution 1 - Design PatternsdfaView Answer on Stackoverflow
Solution 2 - Design PatternsegagaView Answer on Stackoverflow
Solution 3 - Design PatternsDavid MolesView Answer on Stackoverflow
Solution 4 - Design PatternsEd SykesView Answer on Stackoverflow
Solution 5 - Design PatternsMohammad AkbariView Answer on Stackoverflow