| View previous topic :: View next topic |
| Author |
Message |
James Barrett Guest
|
Posted: Sat Jan 05, 2008 11:51 pm Post subject: Pattern for handlng multiple concurrent States |
|
|
Hello, I've been reading up on Design patterns from
various sources, including the GoF as well as some web sites and I'm
not sure at all which ones best fit my scenario. I am confused about how
to handle multiple States that can be active at the same time. Maybe I'm
making this more complicated that it really is, but I want to understand
the patterns and how they work.
I'll use an example of a game entity to explain my scenario.
Suppose I have a Creature class. I create a
State called Roam so that a creature object can move around aimlessly.
Now suppose the creature becomes Poisoned. The
poison will continue to alter the behavior of the creature over time. So
I create a State called Poisoned. I am confused about how to handle
these two states concurrently, because the creature can still Roam while
Poisoned. Even more complicated is the fact that eventually the creature
could move into a Hunting State. So then it would be Hunting while
Poisoned. How is this kind of scenario usually handled? Should Poisoned
be a unique State? Or maybe Poisoned falls under a completely different
design pattern? Maybe Decorator, or Flyweight, Or could I have nested
States? Should my creature class have multiple State pointers to handle
these States? Or should I create a RoamWhilePoisoned State and a
HuntingWhilePoisoned State? Or would Poisoned merely be a boolean
property of each State class? I'm really not sure how to proceed.
The more I think about it, the more I am leaning towards a linked-list
style of pattern for my States (Decorator?), where each state contains a
pointer to the next state. Adding a new state means it gets added to the
pointer in the last State in the list. Calling State->Execute() would
then run it's own logic and then call nextState->Execute(). Transitions
would be tricky, I would have to un-link the state being removed, and
link in the new state.
Would that be the way to do it? What are the pros and cons of doing it
this way? Is this an actual pattern as defined by the GoF or is this
really a combination of patterns?
Thanks,
Jim |
|
| Back to top |
|
 |
| |
Ads |
Advertising
Sponsor
|
|
H. S. Lahman Guest
|
Posted: Mon Jan 07, 2008 3:25 am Post subject: Re: Pattern for handlng multiple concurrent States |
|
|
Responding to Barrett...
| Quote: |
Hello, I've been reading up on Design patterns from
various sources, including the GoF as well as some web sites and I'm
not sure at all which ones best fit my scenario. I am confused about how
to handle multiple States that can be active at the same time. Maybe I'm
making this more complicated that it really is, but I want to understand
the patterns and how they work.
|
First, we need to define what you mean by 'state'. In the conventional
meaning of a state of being, an object can only be in one state at a
time. So we generally use object state machines when we want to deal
with distinct states and the transitions in those state machines
represent problem space constraints on the sequencing of states.
OTOH, the GoF State pattern is really about a notion of 'state' that is
more akin to a role. (IMO, the GoF pattern is actually misnamed and
should be called Role.) Your description below seems to be more akin to
roles that a Creature might take on.
| Quote: |
I'll use an example of a game entity to explain my scenario.
Suppose I have a Creature class. I create a
State called Roam so that a creature object can move around aimlessly.
Now suppose the creature becomes Poisoned. The
poison will continue to alter the behavior of the creature over time. So
I create a State called Poisoned. I am confused about how to handle
these two states concurrently, because the creature can still Roam while
Poisoned. Even more complicated is the fact that eventually the creature
could move into a Hunting State. So then it would be Hunting while
Poisoned. How is this kind of scenario usually handled? Should Poisoned
be a unique State? Or maybe Poisoned falls under a completely different
design pattern? Maybe Decorator, or Flyweight, Or could I have nested
States? Should my creature class have multiple State pointers to handle
these States? Or should I create a RoamWhilePoisoned State and a
HuntingWhilePoisoned State? Or would Poisoned merely be a boolean
property of each State class? I'm really not sure how to proceed.
|
Note that Roaming and Hunting are similar but are not done at the same
time. These activities might well be represented by states in an object
state machine.
Presumably being Poisoned has some affect on the Creature that is
intrinsic to having been poisoned. That affect may or may not be
tailored to what the Creature happens to be doing (e.g., it hunts badly
because its vision is blurred).
There are two ways to handle an affect that spans other
responsibilities. A common approach is to cast the poisoning in terms of
state data that the other responsibilities reference as they do their
things. Thus one might have degreeOfImpairment attribute that each
behavior checks to see how it should be affected. (The
degreeOfImpairment can be updated periodically by a timer object as the
poisoning gets worse over time.)
A second approach is to make Poisoned a GoF State pattern that provides
modified behaviors for things like Roam() and Hunt(). Thus Creature
could have a boolean attribute, poisoned, that would be checked by each
behavior. If TRUE, it would re-dispatch to the corresponding Poisoned
responsibility; otherwise it would execute its own version.
[I am not a fan of the second approach because there is a lot of
coupling between Creature and Poisoned. There is also potentially a lot
of redundancy if both versions of the behavior are largely the same.]
However, I think there is a larger issue that is relevant here. You are
making an assumption that things like Poisoned and Hunting are /ongoing/
activities. In fact, object responsibilities are discrete responses to
something happening externally. A stimulus is applied and the object
responds. Once the object responds, it is done and it just sits there
waiting for another stimulus.
My point is that activities like roaming and hunting are not complex,
monolithic activities (e.g., turn right, then turn left, then left
again, then...). Instead they are a sequence of logically indivisible
responsibilities that are executed as a string of individual responses
to fine-grained stimuli. So when the Creature turns left or right in its
roaming, each turn would be a discrete response to some stimuli (e.g.,
it reached a path intersection).
In fact, any response to being poisoned should be a discrete response to
some stimuli (e.g., passage of an interval of time). For that poisoning
to affect other activities like hunting or roaming, there should be some
mechanism for those discrete responses to be modified by the current
state of the poisoning. That is why the first alternative, casting the
poisoning as state data, is commonly used. That allows other behavior
responses to be modified parametrically without a lot of redundancy.
So I see this problem as not about a design pattern, but more an issue
for problem space abstraction. First, I would look to breaking up
overall, ongoing responsibilities like roaming or hunting into discrete,
logically indivisible behaviors. I would then see a means of casting the
poisoning into state variables so that those individual behaviors can
respond appropriately to the poisoning _when they are triggered_. (As a
bonus, since such behaviors will tend to be simple, dealing with the
effects should be more manageable.)
<aside>
Note that in a well formed OOA/D, very little data is provided in
messages (e.g., method arguments). Methods are expected to access data
that they need synchronously on an as-needed basis. The reason is that
this makes is much easier to map the OOA/D into a concurrent
environment, if necessary at OOP time. So in a well-formed OO
application one influences behaviors parametrically through object
attributes rather than via message data packets. Thus the paradigm
itself strongly encourages abstracting the problem space in terms of
knowledge responsibilities wherever possible.
</aside>
--
There is nothing wrong with me that could
not be cured by a capful of Drano.
H. S. Lahman
hsl@pathfindermda.com
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info@pathfindermda.com for your copy.
Pathfinder is hiring:
http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH |
|
| Back to top |
|
 |
| |
Ads |
Advertising
Sponsor
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|

112 Attacks blocked
Powered by phpBB © 2001, 2005 phpBB Group
|