views:

163

answers:

5

I've used the State pattern to implement a simple finite state machine. Looking at the description given on Wikipedia, and more specifically at the suggested Java implementation, I wondered why classes implementing the State interface (i.e. the various states) are not Singletons?

In the suggested implementation a new State is created whenever a transition occurs. However, one object is sufficient to represent each state. So, why wasting time creating a new instance every time a transition occurs?

+1  A: 

Assume your object has a state. Now what if you need "just one more whole thing like that"?

Pavel Radzivilovsky
Can you explain what you mean by "assume your object has a state"? I have a finite state machine (FSM), which is a set of states. Each state does not change. The state of the FSM is simply it's current state (one of the available states). If the FSM changes, I must change either the transition logic, or the set of states (possibly by adding/removing some). In this context, I think each state can be a Singleton, can't it?
MarcoS
no, because when it's a singleton, you cannot have a clone of your whole state machine object with its state. Singleton = one per application.
Pavel Radzivilovsky
@Pavel: Sure you can; a shallow clone would suffice since states aren't mutable and store no information beyond their identity. Of course, if it's not a pure state-machine (i.e. states are annotated with non-static information).
Eamon Nerbonne
+1  A: 

You may want a 'stateful-State' object (like demonstrated as one example on the references wikipedia page) and in addition you may want to run several state machines of the same type in the same JVM.

This wouldn't be possible if each State was a Singleton.

Andreas_D
+6  A: 

Because each state can store instance variables?

Take a look at the Wikipedia example you reference:

class StateB implements State { 
    private int count=0; 
    public void writeName(StateContext stateContext, String name) { 
        System.out.println(name.toUpperCase()); 
        if(++count>1) { 
            stateContext.setState(new StateA()); 
        }
    }
}

Can you see how it stores a count of the number of times it has been entered?

Now, in a FSM you probably want each state to be idempotent (subsequent calls give the same feedback) but the State pattern is more general. One target use as described on the wikipedia page is:

A clean way for an object to partially change its type at runtime

As most objects probably use their local variables when performing actions, you would want the "changed type" version to use local variables as well.

Graphain
I see the point. Thanks!
MarcoS
A: 

The question should be asked the other way around: why have State as a singleton? A singleton is only needed when you require global access and it is an error to have more than one instance.

It's certainly not an error to have more than one instance of a State, and you also do not require global access, so there is no need to make them singletons.

Dean Harding
Making them "singletons" may have performance benefits, however. If a state is not mutable and stores no per-instance information, then it's essentially just an enumeration value and comparison can occur by-reference - which is very quick - and instance creation/destruction is avoided (lowering GC load).
Eamon Nerbonne
@Eamon Nerbonne: what you describe is exactly my case, and this is why I made my states singletons. However, I understand that in a general case this is not necessarily a good idea: see [Graphain answer above](http://stackoverflow.com/questions/3090943/state-pattern-why-states-are-not-singletons/3090974#3090974).
MarcoS
A: 

If your states don't need machine-specific additional state data, it makes perfect sense to reuse them across machines. That doesn't mean they are Singletons: Singletons also imply global access which you almost never want.

Here's a simple state machine that reuses states, but doesn't make them singletons.

public class SwitchState
{
    public SwitchState(bool isOn)
    {
        mIsOn = isOn;
    }

    public void InitToggleState(SwitchState state)
    {
        mToggleState = toggleState;
    }

    public bool IsOn { get { return mIsOn; } }
    public SwitchState Toggle() { return mToggleState; }

    private SwitchState mToggleState;
    private bool mIsOn;
}

public class LightSwitch
{
    public LightSwitch()
    {
        mState = sOnState;
    }

    public bool IsOn { get { return mState.IsOn; } }

    public void Toggle()
    {
        mState = mState.Toggle();
    }

    static LightSwitch()
    {
        sOnState = new SwitchState(true);
        sOffState = new SwitchState(false);

        sOnState.InitToggleState(sOffState);
        sOffState.InitToggleState(sOnState);
    }

    private static SwitchState sOnState;
    private static SwitchState sOffState;

    private SwitchState mState;
}

You can see there will only be a single on and off state in the entire application regardless of how many LightSwitch instances there are. At the same time, nothing outside of LightSwitch has access to the states, so they aren't singletons. This is a classic example of the Flyweight pattern.

munificent