Correct use of State Pattern

M

mdjj

I want to know if this is a suitable use of the state pattern.

I have a business object that moves between various states during it's
lifecycle.
The actions you can do to the object at each state are not necessarily
identical.
All you can really do is save the object to a persistent store and move
it to the
next state. To move it to the next state you have to have filled in
certain data
that needs to be validated before allowing you to move on.

All the examples i've seen re the State Pattern have similar methods
applying at each
state but the method behaves differently. Potentially I have a Save,
Validate and MoveToNextState methods.

Does my scenario fit the State Pattern or am I trying to fit a square
peg into a round hole?
If it doesn't is their an alternative pattern I should be looking at?

If it does, I was planning on writing seperate State classes but where
do I put my validation?
The validation applies to the business object but is different
depending on what state the BO
is in, therefore it seems sensible to put it in each state class?
 
H

Hendrik Maryns

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
NotDashEscaped: You need GnuPG to verify this message

mdjj schreef:
I want to know if this is a suitable use of the state pattern.

I have a business object that moves between various states during it's
lifecycle.
The actions you can do to the object at each state are not necessarily
identical.
All you can really do is save the object to a persistent store and move
it to the
next state. To move it to the next state you have to have filled in
certain data
that needs to be validated before allowing you to move on.

All the examples i've seen re the State Pattern have similar methods
applying at each
state but the method behaves differently. Potentially I have a Save,
Validate and MoveToNextState methods.

Does my scenario fit the State Pattern or am I trying to fit a square
peg into a round hole?
If it doesn't is their an alternative pattern I should be looking at?

If it does, I was planning on writing seperate State classes but where
do I put my validation?
The validation applies to the business object but is different
depending on what state the BO
is in, therefore it seems sensible to put it in each state class?

Without more information, I'd suggest you have a look at the Mediator
pattern.

H.
--
Hendrik Maryns

==================
www.lieverleven.be
http://aouw.org
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFEJB+te+7xMGD3itQRAqt9AJ42UAAl0zk4fFUPp1COwDtXPc81XwCfXhlO
e8jNC8hp3oNNp2Mn1WECz+Y=
=R1w+
-----END PGP SIGNATURE-----
 
M

mdjj

Thanks I'll look at mediator. Here's an example of what I'm talking
about :

My example relates to the lifecycle of a policy. Someone can make an
enquiry, ask for a quote, take up that quote, decline that quote, take
up the policy etc etc.

Typically they won't complete the whole lifecycle in one go, therefore
at each stage we need to capture some data and store it. The data we
store is fundamentally the same it just gets built on at various
stages. Before we allow them to go to the next stage we have to
validate that they've given us enough info. So all we do at each stage
is either save ,validate or MoveToNextStage. There will probably be
some distinct functionality at various stages getPrice at the Quote
stage for example.

The only thing that's really changing along the way is the state and
some additional data we may hold, it's still a
policy (or potential policy).
 
O

Oliver Wong

mdjj said:
I want to know if this is a suitable use of the state pattern.

I have a business object that moves between various states during it's
lifecycle.
The actions you can do to the object at each state are not necessarily
identical.
All you can really do is save the object to a persistent store and move
it to the
next state. To move it to the next state you have to have filled in
certain data
that needs to be validated before allowing you to move on.

All the examples i've seen re the State Pattern have similar methods
applying at each
state but the method behaves differently. Potentially I have a Save,
Validate and MoveToNextState methods.

Does my scenario fit the State Pattern or am I trying to fit a square
peg into a round hole?
If it doesn't is their an alternative pattern I should be looking at?

If it does, I was planning on writing seperate State classes but where
do I put my validation?
The validation applies to the business object but is different
depending on what state the BO
is in, therefore it seems sensible to put it in each state class?

If my understanding is correct, you are saying that at each state, a
different set of operations are applicable to the business object. Unless
you want to use reflection, you will probably need to have a different
interface (or class) for each state.

As a concrete example, let's say the states are egg -> tadpole -> frog,
and the methods differ consireably from one state to another; e.g.
becomeImpregnated(), hatch(), swim(), eatAlgae(), metamorphose(), hop(),
eatInsects(). The methods should be more or less called in the presented
order, but there may be some slight variantions.

<pseudoCode>
public interface Egg {
public void becomeImpregnated();
public Tadpole hatch();
}

public interface Tadpole {
public void swim();
public void eatAlgae();
public Frog metamorphose();
}

public interface Frog {
public void hop();
public void eatInsects();
}
</pseudoCode>

You could have the same class implement all 3 interfaces, or you could have
a class for each interface.

<pseudoCode>
public class EggImpl implements Egg {
private impregnated = false;
/*package protected*/ String dna;

public EggImpl() {
dna = someRandomSequence();
}

public void becomeImpregnated() {
this.impregnated = true;
dna.modifySomehow();
}

public Tadpole hatch() {
if (!this.impgrenated) {
return null;
}
return new Tadpole(this);
}
}

public class TadpoleImpl implements Tadpole {
/*package protected*/ String dna;
/*package protected*/ Object nutrition;

TadpoleImpl(Egg e) {
/*Package protected constructor*/
this.dna = e.dna;
}

boolean swam = false;
boolean ate = false;

public void swim() {
this.swam = true;
}

public void eatAlgae() {
if (this.swam = true) {
nutrition.modifySomehow()
this.ate = true;
this.swam = false;
}
}

public Frog metamorphose() {
if (!this.ate) {
return null;
}
return new FrogImpl(this);
}
}

etc.
</pseudoCode>

The "3 different classes" approach has each state acting as a factory for
the next state.

<pseudoCode>
public EggTadpoleFrog implements Egg, Tadpole, Frog {
public Tadpole hatch() {
return this;
}

public Frog metamorphose() {
return this;
}

/*Rest of the code is similar to the above*/
}
</pseudoCode>

With 1 class, you're just "re-casting" the object, instead of creating a
new object each time.

By using interfaces, instead of concrete classes, you're free to switch
between these two implementations without affecting the client.

- Oliver
 
O

Oliver Wong

mdjj said:
Thanks I'll look at mediator. Here's an example of what I'm talking
about :

My example relates to the lifecycle of a policy. Someone can make an
enquiry, ask for a quote, take up that quote, decline that quote, take
up the policy etc etc.

Typically they won't complete the whole lifecycle in one go, therefore
at each stage we need to capture some data and store it. The data we
store is fundamentally the same it just gets built on at various
stages. Before we allow them to go to the next stage we have to
validate that they've given us enough info. So all we do at each stage
is either save ,validate or MoveToNextStage. There will probably be
some distinct functionality at various stages getPrice at the Quote
stage for example.

The only thing that's really changing along the way is the state and
some additional data we may hold, it's still a
policy (or potential policy).

I'm not familiar with these "policies" that you speak of, but are you
sure that the data that you're storing is data on the policy, as opposed to
data on the customer?

- Oliver
 
M

mdjj

Yes. It's an insurance policy (sorry didn't make that clear). A
customer 'has a' policy i.e they insure their car. The policy has data
specific to it i.e. amount Insured, what's insured, type of vehicle
etc.

This policy moves states from enquiry to quote etc as described before.
 
R

Roedy Green

Potentially I have a Save,
Validate and MoveToNextState methods.

The primary thing that defines a state pattern is a fairly complicated
rule for nextState that depends only on the current state and current
input.

You probably would not consider it a state pattern if the rule were
simply state = state+1;

Whether you are officially using a state pattern or not, you can still
organise you code the same way, an as enum, with custom methods for
each enum state and some shared methods, perhaps implemented
differently.

A state machine usually has a loop and the object waddles back and
forth between various states, e..g. as you parse a document. In your
case you are going to defrost an object, figure out its next state and
freeze it again. Your outer loop is different from a traditional state
machine, but it the same sort of thinking.
 
R

Roedy Green

You could have the same class implement all 3 interfaces, or you could have
a class for each interface.

Sort of like boy scout merit badges. As pass each stage you attach
another object to the policy with the additional data.
 
M

mdjj

Sort of like boy scout merit badges.

Blimey that takes me back. It's along time since I did my 'Light a fire
whilst tying a knot and observing the weather' badge.

Thanks for your help. It's given me some pointers. Currently the
application I'm working on treats each state as a seperate unconnected
business object (and actually doesn't recognise that each business
object is actually just about the same as the previous one just with a
different state). I'm trying to get back to some commonality hence the
look at the State Pattern.

Actually you made a good point that it doesn't have to strictly be
classed as a State Pattern, I suppose I was a little nervous that I
didn't start off trying to use a pattern that really wasn't covering
what I was trying to achieve.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,781
Messages
2,569,615
Members
45,293
Latest member
Hue Tran

Latest Threads

Top