• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • paul wheaton
  • Ron McLeod
  • Devaka Cooray
Sheriffs:
  • Jeanne Boyarsky
  • Liutauras Vilda
  • Paul Clapham
Saloon Keepers:
  • Tim Holloway
  • Carey Brown
  • Piet Souris
Bartenders:

State Pattern

 
ranger
Posts: 17347
11
Mac IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here's a pattern that I completely understood in HF DP, The gumball machine and its states helped.

Now I am actually trying to implement the State Pattern, but confused.

Here is the scenario, we have a "message" that can change its state. The Message is a Data Transfer Object that is auto-generate, so there wouldn't be a way to add a State object to the instance variables. I could wrap the DTO into another object that holds the DTO and the State object.

Where I am confused is the methods that would need to go into the State interface that the State objects implement.

So there is 5 different states the DTO can be in.

Draft
Completed
Approved
Released
Cancelled.

So there would be five State objects, but when a state changes different possible actions need to take place.

I keep coming to the point where I want add methods for each state to change to

like

changeToDraft()
changeToCompleted() etc....

I know this is wrong, because when I would add a new State object later, i would have to go into all the State objects and add code.

The other thing that comes up is the if..else if...else if syndrome to check what state is changing to what to determine the method to call.

Does anyone have any suggestion for helping understand how to implement the State Pattern for my task?

Thanks

Mark
 
author
Posts: 200
6
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
If every one of your states can potentially change state to every other state, then you're kind of stuck adding code whenever you add a new state. However, it is highly unlikely that *every* state is possible from *every other* state.

Did you do a state diagram before you started to see which state transitions are atually possible?

Then, make each state responsible for determining which states are possible next.

Seems to me that, for instance, draft -> completed is possible, but not draft->approved.

In that case you only need one method in Draft State - it changes to completed. And the Draft State itself is responsible for determining the conditions when it switches state to completed. Your client does not change the state, rather the state itself changes the state.

Hope this helps,

Elisabeth
 
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
See if this turns on any lights ... I have tons of code like this:

We do this to fake polymorphic behavior for DTOs that actually have no behavior. The different behaviors that would normally go into subclasses go into strategies instead.

States could work much the same way. Ooh, you might get

That would model each state knowing what state should come next based on some event. A state could ignore or reject certain events. Kinda violates SRP if the state does anything else useful.
[ December 01, 2004: Message edited by: Stan James ]
 
Mark Spritzler
ranger
Posts: 17347
11
Mac IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Elisabeth Freeman:
If every one of your states can potentially change state to every other state, then you're kind of stuck adding code whenever you add a new state. However, it is highly unlikely that *every* state is possible from *every other* state.

Did you do a state diagram before you started to see which state transitions are atually possible?

Then, make each state responsible for determining which states are possible next.

Seems to me that, for instance, draft -> completed is possible, but not draft->approved.

In that case you only need one method in Draft State - it changes to completed. And the Draft State itself is responsible for determining the conditions when it switches state to completed. Your client does not change the state, rather the state itself changes the state.

Hope this helps,

Elisabeth




Yes, we do have a State diagram, and not every state can be changed to all the other states.

So then what you are saying is that if to get to Completed State, it can only come from Approved or Draft, then the Completed State object would only need two methods to change to those states? What happens if a Released State object is passed to the Completed State object, how would it know what method to call, and send back a failure.

I don't know why I keep confusing myself about this one. I need to look at that chapter again to ask better questions.

I will post again after I finish re-reading the State chapter.

Mark
 
Mark Spritzler
ranger
Posts: 17347
11
Mac IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
OK, I think I know what my problem is. The problem isn't the State classes themselves, but the fact that the methods of the State interface are actions that can occur on the State Machine (the Message in my case). However, there aren't any actions except changing the state itself, no "insertQuarter()" or "turnCrank()" type methods.

If I create a "changeState()" method, then the method would still require the checking of old state versus new state and is it allowed. So that would require constants or multiple if statements in the State object, to check to see if the change is valid.

I don't think in my case the State pattern will work.

Mark
 
Ranch Hand
Posts: 782
Python Chrome Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What events will cause the state to change ? It could be as simple as some Client calling the DTO's getter or setter methods.

You mentioned that the DTOs are auto-generated. Via ant? Xdoclet? Why don't you auto-generate the infrastructure code for the State pattern as well ? Try to hack up an ant task coupled with the state machine compiler to do the job.
 
Ranch Hand
Posts: 76
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


If I create a "changeState()" method, then the method would still require the checking of old state versus new state and is it allowed.


The idea of using events or setters on the "message" is the right way to go.
If the Message gets the .completed() message this should send the "Completed" state to the changeState(State newState) method. That is the simple version. The changeState() method could check if going to the newState from the currentState was valid. This should be able to done with a lookup table. If it is an invalid state, then you would decide whether to throw an exception or keep the state as is or maybe have an InvalidState.

Basically, every arrow/line representing a transition from one state to the next that you modeled has to represented as a method on the Message so it can be told to transition. Otherwise, it will never change. Sort of sounds like the start of a "light bulb" joke.

I remember a friend actually created a multi-dimensional matrix to represent the "State Machine". He would take the inputs run them through the matrix to get either the "next state" or an "invalid state". The machine modeled the processing of a file with different record types. There were set rules about which record type preceeded other record types. This was implemented in C++.

Enjoy the journey, after all you are going to have a solid design when you are finished.
 
Mike Farnham
Ranch Hand
Posts: 76
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
As far as automating the changes, whenever a new state or new transition is introduced, that sounds like something that might be covered by a Rules Engine. There your business logic is stored in XML files. This takes the "if" statements out of your code.

And, each transition in a State Transition diagram is a business rule. Stating that a Draft must be Completed before it can be Approved pretty much sums up the workflow at your organization.

Just a side note, I found that using a whiteboard and mapping out a State Transition diagram with knowledgeable users (Domain knowledge) was a great way to define the requirements. In this case the picture was almost worth a thousand words, but I still had to type it up! Each time I have done this has usually been the most productive IT/Client meetings. Not only do you get the workflow down, but you can also determine what some of the UI terms messages will be, if you are creating a new system. For example, the DRAFT to COMPLETED scenario. The client can say I want that to be FINISHED. And, if you have already coded it, you can have a public/private separation. The public view might be a FINISH button, but this could still call the x.completed() method. Oh the joy! Sort of like the commerical, "What you call maize, we call corn."
 
blacksmith
Posts: 979
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

Just for future reference I would like
to point out the following article. It
might be useful.

Cheers,

Gian
 
Mark Spritzler
ranger
Posts: 17347
11
Mac IntelliJ IDE Spring
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I think that the fact that the only way our state can change is through the operator manually changing the state field, not through other actions. This is why the State Pattern won't work in our case. It just would push the if statements down to a lower level, but you would still need them, so why add the extra levels, when that is not needed.

Mark
 
reply
    Bookmark Topic Watch Topic
  • New Topic