Strategy pattern.... am I on the right track?

Started by
12 comments, last by Nypyren 10 years, 7 months ago

 


void creature_class::listen(){   this->InterfaceListen_strategy->execute();   // place this creature's specific code afterwards, if any, that is invariant}void creature_class::set_listen_strategy( <variables> ){  if( DEAF ) this->IntefaceListenStrategy = DeafListenConcrete;  if( BUFFED ) this->IntefaceListenStrategy = BuffedListenConcrete;  // etc.}
Are you sure you want a public set_listen_strategy()? The listening strategy appears to be a very clear cut example of the most private kind of internal state (of class creature_class):

- Nothing "outside" the creature can reasonably have any say in how it listens to noise.
- Changing the strategy at the wrong time might cause errors (e.g. hearing too much or too little), so it should be encapsulated.
- It's a convenience to organize the listening-related code, and the exact same behaviour could be achieved in completely different ways; there's no reason for outside code to depend on such volatile details.
- The events that can cause a change of InterfaceListen_strategy might instead cause a flag to be set, or something else, or no change; the public interface of the creature should match these events (e.g. making the creature hear a deafening noise, already covered by listen() ) rather than exposing a specific way to implement their consequences and constraining creature_class to use it forever because improper dependencies have been established.

I understand and can appreciate your points. The wisdom of when to use a pattern is something that's acquired through experience. It's hard to make a simple and complete example for something that requires a certain degree of complexity to explain. In responding to the OP, I can only assume that the choice has been made as to warrant the use of a pattern. Saying that, I'll certainly adopt code if it offers material benefit.

Let me respond to your points the best as I understand them:

In my defense, I never provided a full declaration of creature_class::set_listen_strategy. But your point is taken. Reference to setting the strategy pattern should be invisible to things outside of the class that uses it. If I understand your meaning, we should instead supply something like creature_class::is_now_deaf() and then have that function handle whatever state lies beneath whether it be setting a strategy pattern or something else. That makes sense.

I'm not sure what you mean by: "Nothing "outside" the creature can reasonably have any say in how it listens to noise."

When I first read the point I interpreted it as being in direct conflict with your advice to make set_listen_strategy private. But I will assume, that's not what you meant. If you are referring to sending data to the creature class about the external world interacting with it, we could fix it by either providing a parameter that all listen calls use or we can set the appropriate state information through a different method / interface in the creature_class (or its hierarchy) and refer to it indirectly and under the covers.

If I change the strategy at the wrong time it will cause issues. Sure. I agree. But it's also true that if I change that state of any other thing before it is ready to be consumed I would also get unexpected behavior. While this is of concern, I don't see how it is specifically relevant to the strategy pattern. It seems to be a more general issue that you are describing.

You will get no dispute from me about the 'convenience' factor. There are probably an infinite numbers of ways we could organize the code. But that's the point of patterns: flexibility, maintainability, and convenience. Because the OP is referring specifically to the Strategy pattern I can only assume the source of this strategy comes from a well known source. A well known source happens to be the classic GoF book. In it, they specifically give this as a reason to employ the pattern. Under their 'applicability' section these are the reasons they give:


Use the strategy pattern when

-- many related classes differ only in their behavior.  Strategies provide a way to configure a class with one of many behaviors.

-- you need different variants of an algorithm.  For example, you might define algorithms reflecting different space/time trade-offs.  Strategies can be used when these variants are implemented as a class hierarchy of algorithms

-- an algorithm uses data that clients shouldn't know about.  Use the Strategy pattern to avoid exposing complex, algorithm-specific data structures.

-- a class defines many behaviors, and these appear as multiple conditional statements in its operations.  Instead of many conditionals, move related conditional branches into their own Strategy class.

Moderators: This is a quote from the GoF book. I cite fair use but I don't know if this exceeds the bounds you're willing to tolerate. I will comply with requests to remove if I'm breaking a rule.

Back to the discussion. For the creature class it is this last point for which I've decided that the Strategy pattern happens to be useful. Later in their description they give an example of a 'switch' ladder and how the Strategy pattern makes the code easier to understand.

I'm a little unclear about your last point.

I'll add a final thought. Maybe I have it all wrong and you do offer valid points. This creature example is somewhat contrived. I certainly won't be juryrigging Strategy patterns at each and every spot that might avoid 'if-then-else' or 'switch' ladders. After all, there is a cost in factoring code to use any pattern. If we know that creature_class is something that is very well defined and will not change then it's probably not worth any extra management apparatus, It will only get in the way.

I know my response probably appears very defensive. Please receive them only with attempts at giving an earnest, respectable reply. smile.png

Advertisement


I understand and can appreciate your points. The wisdom of when to use a pattern is something that's acquired through experience. It's hard to make a simple and complete example for something that requires a certain degree of complexity to explain. In responding to the OP, I can only assume that the choice has been made as to warrant the use of a pattern. Saying that, I'll certainly adopt code if it offers material benefit.

Actually, the example is arbitrary. I'm not trying to force fit the Strategy pattern in my code (existing or new). I'm actually just wanting to understand the Strategy pattern and see if my example is correct, in the right area, close but no cigar, or just wrong. Of course, I'm looking for feedback or sample code on how to make it better.

Beginner in Game Development?  Read here. And read here.

 


Actually, the example is arbitrary. I'm not trying to force fit the Strategy pattern in my code (existing or new). I'm actually just wanting to understand the Strategy pattern and see if my example is correct, in the right area, close but no cigar, or just wrong. Of course, I'm looking for feedback or sample code on how to make it better.

I would say your example is far from the point.

With strategy the underlying behavior of each object implementing the strategy is different. With yours the underlying behaviors are all the same (hence why you can default construct them.

An OK example is the one used by Wikipedia, which implements a strategy for processing various types of mathematical commands like Add, Subtract, and Multiply. I suggest reading it over.

I would also strongly suggest reading the c2 wiki on strategy and state.

In time the project grows, the ignorance of its devs it shows, with many a convoluted function, it plunges into deep compunction, the price of failure is high, Washu's mirth is nigh.

To me, Strategy is just something you get when you implement two or more algorithms that produce the same effect that can be used interchangeably, where all differences are encapsulated. If the results are different, it's not a Strategy. Interchangeable movement methods like walking vs. flying do totally different things (the flier can FLY), which violates the definition in my mind. That's polymorphism. That's not Strategy. Boyer-Moore vs. every-character string searching is a Strategy.

This topic is closed to new replies.

Advertisement