Jump to content

Talk:State pattern

Page contents not supported in other languages.
From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by 71.228.196.3 (talk) at 15:45, 19 December 2006. The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Edit 2005.10.20: Note that this is NOT the State design pattern, but instead a simple example of inheritance, which is a fundamental object oriented principle that the complete State pattern takes advantage of. For a correct and definitive reference, see "Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. 12.105.87.36 (Moved from main page to talk by BenFrantzDale.)

I disagree. Go back and look at Patterns and note that their use of a connection state mirrors the example given here. Furthermore, they mention a photoshop-style tool as another potential application of the pattern. —BenFrantzDale 02:11, 21 October 2005 (UTC)[reply]
According to this url the important feature that the example on this wiki page is missing is that The difference in behavior should be delegated to objects that represent this state. In other words, an object that just changes its behavior depending on what its internal state is is not really an interesting design pattern. Lots of classes do that. If you want to change the way the class behaves when in a certain state, you may still have to go into the class and make lots of complex changes in lots of different functions, especially if your class has a large interface. What if you have 100 states? What if you want to add a new state that's similar to an existing state except for a few small differences in behavior? With the "State" pattern, these states are represented by objects themselves. If you want to change the way the Context behaves when in a given state, you change the implementation of just that state class. If you want to add a new state that is similar to an existing state, subclass an existing state. Etc.


I will note that the code example on the referenced page has a small error -- it has a class modifying a private member in another class. However, this is obviously just a mistake, the same idea could easily be implemented without this illegal access (for example, have the Handle method return the State object)
I think my example may be ambiguous in that the subclass has some internal state despite following a state pattern at a higher level. I added a second subclass—a rectangular selection class—to clarify. Does this help? —BenFrantzDale 02:42, 24 October 2005 (UTC)[reply]
This example is correct. It closely follows the example shown in the diagram under "Known Uses" of the State Pattern in the Gang of Four book. Would it help if we explictly listed the client like the GoF does? Babomb 19:50, 24 October 2005 (UTC)[reply]
I appreciate the responsiveness here, and after reviewing it more, I understand where you are coming from,and apologize for any confusion.
It is actually the example itself. The model, as described in the book, is an interesting one. In it, the DrawingController is the object containing state, and the Tool is the state itself. In seeing your example without the controller, the usage of the name Tool makes your objects appear to model nouns in a domain. It seems like the Tool is the object with state, and that you're modelling simple static state via inheritance, when in fact the Tool is the state itself for a dynamic parent. I hadn't recalled this example, and didn't make the connection right away. If you look at the TCPConnection example from the book, the fact that the "state" side of the pattern models specific states is more clear, with language such as "Established", "Closed", etc., and if the TCPConnection context object was removed, as in your example, it may have still made some sense.
In your example, you state "The state of the drawing tool is thus represented entirely by an instance of AbstractTool", the fact that the "AbstractTool" refers to the state of the "drawing tool", which is an external object not represented here, is unclear. But, it does say "The state of", so you are definitely correct. It's all in the wording, and that's my fault.
Admittedly, I think the language is ambiguous and misleading, but on the other hand, the message you were trying to express was absolutely right. My suggestion would be to change the example to one where the language more clearly expresses the modelling of states (such as "connected", "running", "offline", "pending", "rerouting", "cancelled", etc.), or at least put special focus on the fact that the Tool classes are modelling the state of some parent object.
And as you proposed, perhaps simply adding the context would solve it.
nanjoutai 03:02, 8 November 2005 (UTC)[reply]
So please somebody with acces to the Socket example do the change! I've somehow taken the idea, and I share that the example, as given, is nothing but inheritance. So I'm willing to see the good example! =) -- User:Euyyn 28-Nov-05
I agree this is Not an example of the state pattern and is inheritance. From the text a reader would assume that each state transition, which is an event/action function, would be bound to a fixed set of events, represented by the methods of the abstract interface, and that only the actions of the transitions, represented by the statements of the overloaded methods, are variable. This is just not the case in the state pattern, but this is the case in inheritance when a method is overloaded. In the state pattern each state transition is defined by a tuple of (event, action) pairs, with an optional guard to handle orthoginal concerns. There is no restriction that the domain of the transitions be restricted as the example and text proports by the use of an interface, thus each state can have it own domain of events that are either the same or different.

my understanding

I don't think the sample here is of the state pattern neither. My understanding is that each of the state in the context space should be represented by a concrete class of the type with its implementation of the action(s) including state change. And the object keeps the current state value throughout the procedure.

I have added a client to the code, which I hope will clear up the confusion. This drawing tools example is very similar to that in the diagram on p. 313 of the GoF book. Babomb 06:25, 18 March 2006 (UTC)[reply]

a printer

I agree your example is not a state pattern, because the "states" (your tools) do not model the transitions. When I use this pattern, not only the operations but also the state transitions are delegated to the states themselves. Here, your DrawingController controls the whole transition table hence you gain almost no expressiveness over a switch statement.

To me, your example is quite as good an example as one for the Strategy pattern.

I don't quite remember the example the GoF use but here is one involving a two-state printer (in Java):

package printer;

public class Printer {
   private PrinterState state;
   public Printer () {
      state = new OnLineState(); // default state is on-line
   }
   public void print (Document doc) {
      state = state.print(doc);
   }
}

interface PrinterState {
   PrinterState print (Document doc);
}

class OnLineState implements PrinterState {
   public PrinterState print (Document doc) {
      PrintState nextState = this;
      try {
         doc.print();
      }
      catch (OffLineException x) { // maybe no more paper?
         nextState = new OffLineState();
      }
      return nextState;
   }
}

class OffLineState implements PrinterState {
   public PrinterState print (Document doc) {
      waitOnlineButton();
      return new OnLineState().print(doc);
   }
   private void waitOnlineButton () {
      // implementation not relevant
   }
}

Hope it helps (you may use this code as you see fit, or even delete it if you find it irrelevant)

--Cadrian 14:40, 20 April 2006 (UTC)[reply]

--Anon I think this version is the best on this discussion page - concise and clear

Another Example

Here is a good example of the state pattern I have from my university notes (hope the lecturer doesn't mind me putting this on here!). I am currently revising my notes and I found this example extremely useful for the state pattern. The other good example is a TCP session because it goes through states in a state machine manner whereby one state initiates the change of state itself.

Anyway, here is the example of a FrameImage and FrameType (the state) pattern. Here the FrameType, the state, can be changed by the user thus making the code a lot simpler when we want to allow the user to be able to quickly change the type of frame we have around an image.

---NOTE: The example below is actually the "bridge" pattern.

class FrameType {
 public:
  virtual void draw_frame(int width, int height)=0;
};

class PlainFrame : public FrameType {
 public:
  virtual void draw_frame(int width, int height);
};

class FancyFrame : public FrameType {
 public:
  virtual void draw_frame(int width, int height);
};

class FramedImage {
 public:
  void draw_frame();
 private:
  FrameType* frametype;
  int width;
  int height;
};

void FramedImage::draw_frame() {
 frametype->draw_frame(width, height);
}


Need Better Example

I am someone that has recently become familiar with the State pattern. I have to agree that the implementation of drawing tools is not a good example problem for this pattern. The key issue is that drawing tools really don't go through state transitions.

Take a digital watch as a better example. As you press various buttons, you enter different modes (or states) where buttons take on different functions. You might enter a time edit mode, or stopwatch mode, or heartrate mode, etc. The user interacts with the digital watch using the same buttons, but they have different meanings in the different contexts. This is a much better example problem to model using the State design pattern.

please comment

Hi All, I am going through different patterns currently. I had tried to implement the State pattern with this example. Please comment whether this example is correct or not. BTW, I have taken it from GOF's book. //Example of State Pattern

#include <iostream.h>

class Context;
class State;
class FirstState;
class SecondState;
class ThirdState;

class State
{
public:
	//State(Context* t):m_t(t){}
	virtual void FirstFunction(Context* t){}//has been implemented in the first state
	virtual void SecondFunction(Context* t){}//has been implemented in the second state
	virtual void ThirdFunction(Context* t){}//has been implemented in the thirs state

protected:
	void StateChange(Context* t, State* s);//{t->StateChange(s);}//has been implemented later
private:
	//Context* m_t;
};


class FirstState : public State
{
public:
	
	FirstState(){}

	void FirstFunction(Context* t);
	/*
	{
		cout<<"Inside first state. It will turn on second state."<<endl;
		StateChange(t, SecondState::Instance());
	}
	*/

	static State* Instance()
	{
		return new FirstState();
		/*
		if(FirstStateInstance == 0)
			FirstStateInstance =  new FirstState();
		return FirstStateInstance;
		*/
	}
private:
	static State* FirstStateInstance;
	
};

class SecondState : public State
{
public:
	SecondState(){}

	void  SecondFunction(Context* t);
	/*	
	{
		cout<<"Inside second state. It will turn on third state."<<endl;
		t->ChangeState(ThirdState::Instance());
	}
	*/
	

	static State* Instance()
	{
		return new SecondState();
		/*
		if(instance == 0)
			instance =  new SecondState();
		return instance;
		*/
	}
private:
	static State* instance;
};


class ThirdState : public State
{
public:

	ThirdState(){}
	void ThirdFunction(Context* t)
	{
		cout<<"Inside third cum last state."<<endl;
	}

	static State* Instance()
	{
		/*
		if(instance == 0)
			instance =  new ThirdState();
		return instance;
		*/
		return new ThirdState();
	}
private:
	static State* instance;
};


//enum PresentState{State1 = FirstState::Instance(), State2 = SecondState::Instance(), State3 = ThirdState::Instance()};

class Context
{
public:
	Context() {stateObj = FirstState::Instance();}
	void FirstFunction()
	{
		stateObj->FirstFunction(this);
		SecondFunction();
	}
	void SecondFunction()
	{
		
		stateObj->SecondFunction(this);
		ThirdFunction();
	}
	
	void ThirdFunction()
	{
		stateObj->ThirdFunction(this);
	}

	void StateChange(State* s){stateObj = s;}
	
private:
	State* stateObj;

};

void State::StateChange(Context* t, State* s){t->StateChange(s);}

void FirstState::FirstFunction(Context* t)
{
	cout<<"Inside first state. It will turn on second state."<<endl;
	StateChange(t, SecondState::Instance());
}

void  SecondState::SecondFunction(Context* t)
{
	cout<<"Inside second state. It will turn on third state."<<endl;
	t->StateChange(ThirdState::Instance());
}

void main()
{
	Context* context = new Context();
	context->FirstFunction();
}
That looks about right. Do note that you leak memory, though. Obviously you leak the Context you new in main() (which doesn't really matter here but is sloppy), but you also haven't defined a destructor for Context so it's not clear who should be deleting the State a Context has a pointer to. Since the State objects appear to be singletons, I'd guess you don't plan to delete them, but if they are singletons, they should have a private destructor so you don't accidentally make other instances of them. Also, you'll need to initialize the instance pointers to NULL or else checking for nullness won't do what you want. —Ben FrantzDale 11:32, 19 June 2006 (UTC)[reply]

Internal State vs Behavioural Strategy

This is definitely not a State pattern realization. States represent internal state of a system that alters/transitions over interactions, thereby altering behaviour. The crucial point here is that States must be transitory and the transitions must be internal to the object whose state is being abstracted.

The exapmle presented is clearly a realization of a Strategy pattern where the DrawingController abstracts mouse interaction into a generic Tool with two Tool implementations that exhibit different interaction behaviours. Neither Tool transitions into the other, nor is the Tool interface capable of transitions.

The State pattern is actually a modelling of UML State charts. Hence the necessity of internal event-based transitions.

PS- The Tool analogy was more aptly used in GoF as a realization of the Prototype pattern. --203.197.90.149 07:48, 23 June 2006 (UTC)[reply]

I maintain that the example is a realization of the State pattern, and refer to the similar example on p. 313 of GoF. The current tool selected represents the state of the drawing controller. I believe the confusion stems merely from the way the example is presented.

The Tool interface need not be capable of transitions. From p. 308 of GoF, "The State pattern does not specify which participant defines the criteria for state transitions. If the criteria are fixed, then they can be implemented entirely in the Context."

Nevertheless, I would not be adverse to a replacement example if only to end this argument. By all means, go ahead and write one. --Babomb 23:11, 23 June 2006 (UTC)[reply]

How about this implementation

Please comment on this Sample Example Dear All, Here is my version of the state Pattern. Please comment on this. Previously I submitted another sample, but this one is implemented differently. I also wanted to upload the class diagrams and the sequence diagram of this sample. But I am not sure how to do that.

#include <iostream.h>

class Context;

class State;

class FirstState;

class SecondState;

class ThirdState;

class State

{

public:

	virtual void FirstFunction(Context* t){}//this will implement the function of the first state

	virtual void SecondFunction(Context* t){}//this will implement the function of the second state

	virtual void ThirdFunction(Context* t){}//this will implement the function of the third state

};


class FirstState : public State

{
public:
	
	FirstState(){}

	void FirstFunction(Context* t);//Implementation later in the file
	
	static State* Instance()
	{
		if(FirstStateInstance == NULL)

			FirstStateInstance =  new FirstState();

		return FirstStateInstance;
		
	}
private:

	static State* FirstStateInstance;

	~FirstState(){};
	
};

State* FirstState::FirstStateInstance = NULL;

class SecondState : public State

{

public:

	SecondState(){}

	void  SecondFunction(Context* t);//Implementation later in the file
		
	static State* Instance()
	
        {

		if(SecondStateInstance == NULL)

			SecondStateInstance =  new SecondState();

		return SecondStateInstance;
		
	}
private:

	static State* SecondStateInstance;

	~SecondState(){}

};

State* SecondState::SecondStateInstance = NULL;

class ThirdState : public State

{

public:

	ThirdState(){}

	void ThirdFunction(Context* t)
	
        {

		cout<<"Inside third cum last state."<<endl;

	}

	static State* Instance()

	{
		
		if(ThirdStateInstance == 0)

			ThirdStateInstance =  new ThirdState();

		return ThirdStateInstance;

		}

private:

	static State* ThirdStateInstance;

	~ThirdState(){}

};

State* ThirdState::ThirdStateInstance = NULL;

class Context

{

public:

	enum EState{EFirstState,ESecondState,EThirdState};

	Context()
 
	{

		stateObj = FirstState::Instance();

		PresentState = EFirstState;
	
       }

	void Run()

	{

		switch(PresentState)

		{

		case EFirstState:

			stateObj->FirstFunction(this);

			break;

		case ESecondState:

			stateObj->SecondFunction(this);

			break;

		case EThirdState:

			stateObj->ThirdFunction(this);

                        break;
		
                }

	}

	void StateChange(State* s, EState state)

	{

		stateObj = s;

		PresentState = state;
	
       }

	~Context()
	
         {

		delete stateObj;

		stateObj = NULL;
	
          }
	
private:

	State* stateObj;

	int PresentState;

};

void FirstState::FirstFunction(Context* t)

{

	cout<<"Inside first state. It will turn on second state."<<endl;

	t->StateChange(SecondState::Instance(), t->ESecondState);

	t->Run();

}

void  SecondState::SecondFunction(Context* t)

{
	cout<<"Inside second state. It will turn on third state."<<endl;

	t->StateChange(ThirdState::Instance(), t->EThirdState);

	t->Run();

}

void main()

{

	Context* context = new Context();

	context->Run();

	delete context;
}


--Som mukhopadhyay 11:32, 17 July 2006 (UTC)[reply]

I would prefer a more concrete example, whether a socket or something silly like Bruce Eckel's of a princess kissing a frog. Also, I don't like that you have conditional logic inside the context that determines the function to call based on the state. One of the main points of the state pattern is to remove this sort of conditional logic, e.g.,

--NOTE: the code below is actually the "template method" pattern

class State

{

public:

	virtual void SomeFunction(Context* t){}

};

...

void Context::Run()

{
	stateObj->SomeFunction(this);
}
...

void FirstState::SomeFunction(Context* t)

{

	cout<<"Inside first state. It will turn on second state."<<endl;

	t->StateChange(SecondState::Instance(), t->ESecondState);

	t->Run();

}

void SecondState::SomeFunction(Context* t)

{
	cout<<"Inside second state. It will turn on third state."<<endl;

	t->StateChange(ThirdState::Instance(), t->EThirdState);

	t->Run();

}

void ThirdState::SomeFunction(Context* t)

{
	cout<<"Inside third state."<<endl;

}

--Babomb 01:30, 19 July 2006 (UTC)[reply]


TCPConnection class the GoF book

In the hope this helps the discussion a bit, this is the code copied from the book (Design Patterns : elements of reusable object-oriented software / Erich Gamma [et al.] ISBN 0-201-63361-2 pages 309 through 312), but without the explanations that are between the code snippets:

class TCPOctetStream;
class TCPState;

class TCPConnection {
public:
	TCPConnection();
	
	void ActiveOpen();
	void PassiveOpen();
	void Close();
	void Send();
	void Acknowledge();
	void Synchronize();
	
	void ProcessOctet(TCPOctetStream*);
private:
	friend class TCPState;
	void ChangeState(TCPState*);
private:
	TCPState* _state;
}

{ ------------------------------------------------------------------ }

class TCPState {
public:
	virtual void Transmit(TCPConnection*, TCPOctetStream*);
	virtual void ActiveOpen(TCPConnection*);
	virtual void PassiveOpen(TCPConnection*);
	virtual void Close(TCPConnection*);
	virtual void Synchronize(TCPConnection*);
	virtual void Acknowledge(TCPConnection*);	
	virtual void Send(TCPConnection*);
protected:
	void ChangeState(TCPConnection*, TCPState*);
}

{ ------------------------------------------------------------------ }

TCPConnection::TCPConnection () {
	_state = TCPClosed::Instance();
}

void TCPConnection::ChangeState (TCPState* s) {
	_state = s;
}

void TCPConnection::ActiveOpen () {
	_state->ActiveOpen(this);
}

void TCPConnection::PassiveOpen () {
	_state->PassiveOpen(this);
}

void TCPConnection::Close () {
	_state->Close(this);
}

void TCPConnection::Acknowledge () {
	_state->Acknowledge(this);
}

void TCPConnection::Synchronize () {
	_state->Synchronize(this);
}

{ ------------------------------------------------------------------ }

void TCPState::Transmit(TCPConnection*, TCPOctetStream*) { }
void TCPState::ActiveOpen(TCPConnection*) { }
void TCPState::PassiveOpen(TCPConnection*) { }
void TCPState::Close(TCPConnection*) { }
void TCPState::Synchronize(TCPConnection*) { }

void TCPState::ChangeState (TCPConnection* t, TCPState* s) {
	t->ChangeState(s);
}

{ ------------------------------------------------------------------ }

class TCPEstablished : public TCPState {
public:
	static TCPState* Instance();
	
	virtual void Transmit(TCPConnection*, TCPOctetStream*);
	virtual void Close(TCPConnection*);
}

class TCPListen : public TCPState {
public:
	static TCPState* Instance();
	
	virtual void Send(TCPConnection*, TCPOctetStream*);
	// ...
}

class TCPClosed : public TCPState {
public:
	static TCPState* Instance();
	
	virtual void ActiveOpen(TCPConnection*);
	virtual void PassiveOpen(TCPConnection*);
	// ...
}

{ ------------------------------------------------------------------ }

void TCPClosed::ActiveOpen (TCPConnection* t) {
	// send SYN, receive SYN, ACK, etc.
	
	ChangeState(t, TCPEstablished::Instance());
}

void TCPClosed::PassiveOpen (TCPConnection* t) {
	ChangeState(t, TCPListen::Instance());
}

void TCPEstablished::Close (TCPConnection* t) {
	// send FIN, receive ACK of FIN
	
	ChangeState(t, TCPListen::Instance());
}

void TCPEstablished::Transmit (TCPConnection* t, TCPOctetStream* o) {
	t->ProcessOctet(o);
}

void TCPListen::Send (TCPConnection* t) {
	// send SYN, receive SYN, ACK, etc.
	
	ChangeState(t, TCPEstablished::Instance());
}

83.80.64.20 13:54, 15 September 2006 (UTC)[reply]