3

Firstly, can anyone explain how a state object can be shared when the state object has no instance variables ?

This text is taken from GOF, page 308, item 3 (consequences section):

The state object can be shared. If state objects have no instance variabkes - that is, the state they represent is encoded entirely in their type - then contexts can share a state object. When states are shared in this way, they are essentially flyweight.

Can anyone explain this text ?

Secondly, what are the approaches to the state transition decision? I mean the decision of which next state to propagate?

Please help. Thanks.

jaco0646
  • 15,303
  • 7
  • 59
  • 83
nicholas
  • 2,581
  • 14
  • 66
  • 104
  • Can you explain your second question. Normally a state system doesn't make the decision as to what state to change into - that's driven from outside the state system. All it does is define the states and the transitions between them. – jon hanson Jul 02 '10 at 12:57
  • BTW, this doesn't really have much to do with C++. – jon hanson Jul 02 '10 at 12:58
  • AS you all know, the state pattern doesn't defined the state transition method. Therefore, i wonder what are the approach to code the state transition with state pattern ? Please help. Thanks. – nicholas Jul 03 '10 at 03:31
  • How about the method describe in here http://stackoverflow.com/questions/3015087/transition-methods-in-state-design-pattern ? – nicholas Jul 03 '10 at 03:49

2 Answers2

2

The paragraph is basically saying that you encode your states as individual classes - then the instance type is the "state" and the classes don't need any instance variables because their type encodes all the information you need.

E.g say I want to have three states "Open", "Active" and "Closed". I might define the following classes:

abstract class State {};

class Open extends State {

  public Open() {}

}

class Active extends State {

  public Active() {}

}

class Closed extends State {

  public Closed() {}

}

--

Another option - I'd suspect this is the combination with flyweight being hinted at in the GOF text would be to create a state class which a bunch of static members (one for each state) which can then be shared -

public class State {

  private string name;

  private State(String name) {
    this.name = name;
  }

  public final static State OPEN = new State("Open");
  public final static State ACTIVE = new State("Active");
  public final static State CLOSED = new State("Closed");

}

I had to go digging to remind myself of how all this stuff worked in detail. Kerievsky has a good description of this (I've heavily borrowed from one of his examples above!) and how the state transitions can be handled by sub-classing from the state class, to create classes that manage each transition. See "Refactoring to Patterns" (ISBN: 0321213351)

EDIT(2): His web site has a class diagram for his example - http://www.industriallogic.com/xp/refactoring/alteringConditionalsWithState.html

alt text

Community
  • 1
  • 1
2

In the state pattern you have an represent the state of an object by using state-objects. These state-objects represent a certain state, but they do not have any mutable state of their own. This means they never change. Therefore, any number of objects can use the same state-object at the same time (even from different threads). If the state-object had mutable state, other objects would have to worry about their state-object being changed from elsewhere.

The using of one object instance by many others can be seen as an instance of the flyweight-pattern.

As for the second part of your question, here is an example:

class SomeStateMachine;

class AbstractState {
    // abstract baseclass for all state-classes
    void input(const std::string & data, SomeStateMachine & caller) = 0;
}

class FinalState : public AbstractState {
    FinalState * getInstance(); // always returns same instance
}

class InitialState : public AbstractState {
public:
    InitialState * getInstance(); // always returns same instance
    void input(const std::string & data, SomeStateMachine & caller) {
        std::cout << data << std::endl;
        caller.m_State = FinalState::getInstance();
    }
}

class SomeStateMachine {
public:
    SomeStateMachine() : m_State(InitialState::getInstance())
    void input(const std::string & data) {
        m_State->input(data, *this);
    }
private:
    friend class InitialState;
    AbstractState * m_State;
};

So you basically pass a reference to the calling object to every method of your state-object. This way, the state-object is able to change the state of the caller when needed. This example might not be very beautiful, but I hope you get the idea.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283