Talk:State pattern
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)
- 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)
- 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)
- 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 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.
- 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)
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)
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.
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
younew
inmain()
(which doesn't really matter here but is sloppy), but you also haven't defined a destructor forContext
so it's not clear who should be deleting theState
aContext
has a pointer to. Since theState
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 toNULL
or else checking for nullness won't do what you want. —Ben FrantzDale 11:32, 19 June 2006 (UTC)
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 actuall 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)
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)
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); } } 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; }