|
Prev: Q: the dreaded diamond...
Next: FINAL CfIP, Conference Reliable Software Technologies, Ada-Europe 2008
From: James Barrett on 5 Jan 2008 19:06 Hi, I posted my questions to comp.patterns, but seeing that the recent posts seem to be spam, I wanted to try posting here. I hope this is not off topic, but I rally would like to discuss this. 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
From: Daniel T. on 5 Jan 2008 22:02 James Barrett <xucaen(a)comcast.net> wrote: > 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. You may very well be making it more complicated, but maybe not. :-) > 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? The state pattern works well when you have a class where is seems that in every method you are deciding behavior based on a particular field or set of fields. To modify your example... Let's say we have a Creature class and they can be drugged, there are a number of different drugs, each with its own effect on the creatures behavior, multiple drugs have added effect, and you want to be able to add new drugs easily in the future... Would such a scenario fit what you are thinking about? > Maybe Decorator, or Flyweight, Or could I have nested States? Decorator is something that outsiders add to the object to change how it reacts to stimuli. Flyweight is generally good when you are going to have a large number of objects but they will be in just a few states (and once created they don't change state.) I don't think Decorator would be approprate. Flyweight might be approprate, but I don't think it answers the question at hand... > 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. As always, that depends... A situation where you have to add multiple classes everytime you want to add a conceptual state is probably not best (i.e., When I add the "Molting" state, will I then have to add a "RoamWhileMolting", "RoamWhilePoisendAndMolting", "HuntingWhilePoisendAndMolting", &c.?) Same with the boolean property of each State class. Are you having to add a new boolean property to multiple classes every time you add a state? > The more I think about it, the more I am leaning towards a > linked-list style of pattern for my States (Decorator?), Sounds more like a chain of responsibility... > 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. Well, using the example I provided. Let's say the creature moves, and how far it moves depends in part on what drugs are affecting it, some make it go faster, some make it go slower... I would be inclined to do something like this: [Creature]<>--->*[Drug] Where Drug has a bunch of sub-classes, one for each type of drug. The creature would iterate through all the drugs affecting it, calling each.affectSpeed( baseSpeed ); > 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? The idea you are thinking of would be a combination of State and Chain of Responsibility I think.
From: James Barrett on 5 Jan 2008 22:21 Stefan Ram wrote: > James Barrett writes: >> I am confused about how to handle multiple States that can be >> active at the same time. > > A system might be in a single state at any instant of time. > That's what I always thought. So, perhaps my Creature example by having Roam and Poisoned at the same time are not states at all. > The set of all states of a system usually has more than > one element, because otherwise the concept of state is useless. > I'm not sure what that means. > A state is like a value, so it usually is not said to > be �active�. I take this �active� to mean that this > is the state of its system at the current instance. > Yes, that is what I meant, the state at the current instance. I apologize for not using better terms. > But you can always rename your states to �substates� and > investigate a new set of states that is the power set > of the set of substate. Then, a state { s(0), s(1), ... s(n-1) } > is a set of substates. Are you saying that I could have a set of substates, and that the set itself is considered to be a single state? I think that when one of the substates transitions, I would need to search the set for the substate, end that substate, and then remove it from the set. Then I would need to add the new substate to the set. > > class Creature > { private boolean isHunting; > private boolean isRoaming; > ... } > > I do not get the problem. Is something wrong with this > simple approach? I am learning how to do this in an Object Oriented way. Using boolean variables is not very extenisble. I would need to change Creature every time I added a new substate. By using objects as substates, Creature never has to be changed again when new substates are added. > > But you should try to keep things as simple as possible and > refrain from run-time flexibility whenever a static approach > is sufficient. If states or substates are going to transition randomly or transition based on user input, would I not want a dynamic run-time approach? > > This is one approach to a field known as �object > oriented design�. > Yes, I have heard of that somewhere, but can't seem to recall where. ;-) (joking) Thank you Stefan, you have given me something new to think about. Perhaps my Creature example is not an example of State at all, but rather some other design pattern. I would like to implement some type of pluggable objects so that the system can be extended later without changing existing code. Do you think another design pattern would fit my example? Thanks! Jim
From: Patrick May on 6 Jan 2008 12:40 James Barrett <xucaen(a)comcast.net> writes: > 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. What are you trying to achieve with these states? If your goal is to allow the addition of new states and new behavior based on those states without modification of the Creature class, to respect the Open Closed Principle, in other words, then it would make sense to maintain an extensible set of states associated with each Creature instance. New functionality can then just check the state, or property, list to determine the appropriate behavior. A more interesting question is how to modify existing behavior based on new states that didn't exist when the original behavior was implemented. For example, if Poisoned is a new possible attribute of a Creature and if poisoned creatures are less successful when hunting, the hunt() method needs to somehow take that into account. Solving this in the general case is non-trivial. Your focus on states suggests that you may be driving your design from a data structure perspective. If that's the case, you might get some insight by focusing on the behaviors of your system and introducing state-like attributes only as and when required by the desired behavior. Regards, Patrick ------------------------------------------------------------------------ S P Engineering, Inc. | Large scale, mission-critical, distributed OO | systems design and implementation. pjm(a)spe.com | (C++, Java, Common Lisp, Jini, middleware, SOA)
From: James Barrett on 6 Jan 2008 17:23 Patrick May wrote: > Solving this in the general case is non-trivial. Your focus on > states suggests that you may be driving your design from a data > structure perspective. My focus seems to be on State because I thought this was a State problem. I am beginning to wonder if my example is in fact an example of State or something else. > If that's the case, you might get some insight > by focusing on the behaviors of your system and introducing state-like > attributes only as and when required by the desired behavior. > So in other words, modify the Creature class and/or existing State classes to add new behaviors? I'm concerned that if I introduce some new behaviors later, I will have many classes to modify. I think my biggest confusion is deciding what pattern or structure it is that controls behavior when there seem to be more than one State (property or attribute?) controlling that behavior. I keep reading that you can have only one State at a time, but that seem to be not true. So either there is more to State than what I have read, or my example is not one of State. Is Poisoned really a State? I can see that in the future there could be others like Hungry, Injured, Sad, Angry.. and possibly more. Are those really States or what are they? Jim
|
Next
|
Last
Pages: 1 2 Prev: Q: the dreaded diamond... Next: FINAL CfIP, Conference Reliable Software Technologies, Ada-Europe 2008 |