Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way, using the "State" design pattern, to change states?

My current understanding of the State design pattern is basically this:

Encapsulate all of the behavior of an object in a particular state in an object. Delegate requests to the "Current" state object.

My question is: What is the best way to handle state transitions? In my case, it is likely that "Current" state object will be the one who decides to what other state we need to transition to. I've thought of 2 ways of implementing this:

  1. The state objects methods can return some particular value that means "I'm requesting a state transition". The main object can then query the current state for what new state we should transition to, call ChangeState(), and then route the original request to the new state.

  2. The state object itself can call ChangeState() on the parent, and then itself pass the request that caused the state change on to the new object.

Scenario 2 has the advantage that the main object needs only ever delegate requests to the "Current" state (it internally will handle any necessary state transitions). It is also perhaps a little less obvious.

I'm hoping there are known better ways of handling this scenario. What do you think?

like image 363
dicroce Avatar asked Jan 20 '10 22:01

dicroce


People also ask

How do you use state design patterns?

State design pattern is used when an Object changes its behavior based on its internal state. If we have to change behavior of an object based on its state, we can have a state variable in the Object and use if-else condition block to perform different actions based on the state.

What is the purpose of the state design pattern?

The main purpose of the state design pattern is to allow objects to change their behaviour based on the current state. The state information is determined at and can be changed at runtime, which allows behaviour to be modified dynamically, making it seem as if the object has changed classes.

What kind of problem does the State pattern solve?

The state pattern is set to solve two main problems: An object should change its behavior when its internal state changes. State-specific behavior should be defined independently. That is, adding new states should not affect the behavior of existing states.

When should a developer use the State pattern?

State design pattern is one of the behavioral design pattern. State design pattern is used when an Object change its behavior based on its internal state.


2 Answers

I prefere that state method returns new state object (it reduces coupling and more appropriate to S.O.L.I.D. principles).

Here example (this idea uses in real project):

class ExternalContext {
    //...
}

class Entity
{
    public Entity(ExternalContext context)
    {
        //Creating current state with factory method
        state = EntityState.Create(context);
    }

    public void ChangeEntity(ExternalContext context)
    {
        state = state.Change(context);
    }

    private EntityState state;
}

abstract class EntityState
{
    public abstract EntityState Change(ExternalContext externalContext);
    public static EntityState Create(ExternalContext externalContext);
}
class EntityState1 : EntityState {
    public override EntityState Change(ExternalContext externalContext) {
        //..
    }
}
like image 112
Sergey Teplyakov Avatar answered Oct 20 '22 20:10

Sergey Teplyakov


I think you are perhaps limiting yourself to thinking only in terms of the objects implementing the state pattern (Context object and State objects). This is not the case, and there is other objects involved (Clients). It is possible, that the client, which holds a reference to the context object, should have the responsibility of transitioning state.

Consider this made up example:

// Paintbrush is the context object
class Paintbrush {
    // The State object, ColourState would be the abstraction
    private ColourState colourState; 

    // ... other class stuff

    public paint() {
        // Delegation to the state object
        this.colourState.paintInYourSpecificColour(); 
    }

    public void setColourState(ColourState newState) {
        this.colourState = newState;
    }
}

This should be enough implementation for the context object. Note that neither colourState nor the Paintbrush class have any knowledge of state transitions. This is to reduce the number of responsibilities, as well as to provide a more flexible design.

Basically, changes of state could be the responsibility for the calling class. How this is actually achieved in code is implementation detail, but the important thing to note is that neither the context object nor the state object have a responsibility for transitioning state.

I'm trying to make sure I don't use a Strawman argument, but I'll continue to run with the example. Say at different points you wanted to paint different patterns, and the colours used must be in a specific order, your client would decide when to change state, like this:

public void paintRainbow() {
    paintbrush.setColourState(new RedColourState());
    // do painting...
    // Change state to next colour
    paintbrush.setColourState(new OrangeColourState());
    // Chane state again, and so on...
}

You could have the order of colours specified by the state or the context object, ie. have a subclass of Paintbrush called RainbowPaintbrush, and it would pick the next colour. Or your state objects could pick the next state, in which case you would have to have a RedRainbowColourState, which knew the next state was OrangeRainbowColourState and so on. But the problem with both these examples is that you have to go in and modify (by extension) both the context and the state objects to achieve a different set of transitions. However, if neither know the transitions, and that is the responsibility of the calling class, this can be done without changing the state or context object. Ie.

public void paintChessboard() {
    paintbrush.setColourState(blackColourState);
    // do painting...
    // change state
    paintbrush.setColourState(whiteColourState);
    // etc...
}

This is a simplified example, but it generally holds.

A quick read of Wikipedia's example of the State pattern shows that individual states have knowledge of the next state, so I don't think it's invalid do so. I guess overall it's a tradeoff of where you want the control to be, and how that will fit into your problem. This is how using the concrete state objects to transition would fit into my lame example:

public class RedRainbowColourState implements ColourState {
    public void doPaint(Paintbrush paintbrush) {
        // do painting
        ColourState nextStateInRainbow = new OrangePaintbrushColourState();
        paintbrush.setColourState(nextStateInRainbow);
    }  

But note the explosion of state classes that will be required to transition through all the states using this way. However, an advantage here is that the client can be relieved of responsibility and knowledge of how to create the individual states. In your situation, that may be better way to transition.


To summarise, you can let the individual states perform the transition, or even the context object. Another choice is to let the client handle state transitions.

like image 2
Grundlefleck Avatar answered Oct 20 '22 21:10

Grundlefleck