Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strategy Design Pattern- choosing between strategies with counters

I am programming in Java but this is a more of a design question so any OO programmer could probably answer this question. I have a question concerning the Strategy design pattern. Here are several inks I have found useful:

  1. Strategy Pattern Explained-OO Design.

I am using the strategy pattern twice with one group of four strategies and one group of three. In each case I am deciding which strategy to use by maintaining a decaying counter. if the strategy the software decides to use is successful then the counter is incremented by one. If the strategy used is not successful then the counter is decremented by one. Regardless of success or failure ALL counters are multiplied by a number around .9 to "decay" the counters over time. The software will choose which strategy to use based on which strategy has the highest counter. An example of my very simple UML is shown below:

Example UML.

And in Link form (for easier reading): Example UML

The UML above is the mockup I would like to use. If you can't tell from the above UML, I am writing a Rock, Paper, Scissors game with the intention of beating all of my friends.

Now, on to the problem:

I cannot decide how to implement the "counter system" for deciding which strategy to use. I was thinking about some kind of "data" class where all counters and history strings could be stored, but that just seemed clunky to me. At all times I am maintaining about 2 strings and about eight counters (maybe more maybe less). That is why I was thinking about a "data" class where everything could be stored. I could just instantiate the class to be used in the chooseStrategy() and chooseMetaStrategy() methods, but I just don't know. This is my first project that I will be working on my own for and I just cannot decide on anything. I feel like there is definitely a better solution but I am not experienced enough to know.

Thanks!

------------------------------------follow-up 1--------------------------------------------

Thank you so very much on everyone's answers and kind words. I do have a few follow up questions though. I am new to StackOverflow (and loving it) so if this is not the correct place for a followup question please let me know. I am editing my original post because my follow-up is a little lengthy.

I was looking into Paul Sonier's advice about using the composite pattern and it looked very interesting (thanks Paul!). For the purpose of the HistoryMatching and "intelligent" AntiRotation strategies I want to implement a string of all opponent plays accessible to both classes. Also, I want the history string to be edited no matter what strategy my program played so that I can keep an accurate record of the opponent's plays. The more comprehensive the string (actually I will probably use a LinkedList but if anyone knows of a better (sub-String/sub-List) search method/collection please let me know) the better the strategy can predict the opponent's behavior.

I was wondering how I could implement this "string" or collection while still using the composite pattern.

Also, TheCapn brought up that it would be a good idea to store different counters and history collections for each opponent. Any thought on how to implement this with the composite pattern?

like image 307
Matthew Kemnetz Avatar asked Jul 07 '11 16:07

Matthew Kemnetz


People also ask

In which scenarios should one select a strategy pattern?

Use the Strategy pattern when you want to use different variants of an algorithm within an object and be able to switch from one algorithm to another during runtime. Use the Strategy when you have a lot of similar classes that only differ in the way they execute some behavior.

Can strategy pattern have multiple methods?

No you can have more than one method on your strategy interface. However, in order for your strategy object to actually use the Strategy pattern, at least one of the method implementations should differ between the different strategies.

What is the solution to the strategy design pattern?

Solution with strategy design pattern To implement the solution, let's design one participant one at a time. ISocialMediaStrategy – The interface which abstract the operation. SocialMediaContext – The context which determines the implementation. Implementations – Various implementations of ISocialMediaStrategy .

What problem does strategy design pattern solve?

The strategy pattern is used to solve problems that might (or is foreseen they might) be implemented or solved by different strategies and that possess a clearly defined interface for such cases.


2 Answers

Ideally, the intent is to have the counters be associated with the strategies, because they're counting the successes of the strategies. However, you don't necessarily want the strategies to know anything about the fact that they're being counted. To me, this indicates a Composite pattern, whereby you wrap your Strategy class in a class which has logic for tracking / degrading / modifying the count of usages.

This gives you locality (the count is stored with the strategy it's counting) and functional composition (count functionality is encapsulated in the composition class). As well, it maintains the isolation of the strategy class from other influences.

Your design breakdown so far looks good; you're certainly on a good and interesting path. Hope this helps!

like image 185
Paul Sonier Avatar answered Nov 13 '22 11:11

Paul Sonier


Firstly, i'd suggest you try something a bit simpler: move-to-front. Keep your strategies in a list, initially in an arbitrary order. Work through them like this:

List<Strategy> strategies;
Strategy successfulStrategy = null;
for (Strategy strategy: strategies) {
    boolean success = strategy.attempt();
    if (success) {
        break;
        successfulStrategy = strategy;
    }
}
if (successfulStrategy == null) throw new NoSuccessfulStrategyException();
// now move the successful strategy to the front of the list
strategies.remove(successfulStrategy);
strategies.add(0, successfulStrategy);

Basically, a successful strategy moves straight to the head of the queue; over time, good strategies accumulate near the head. It's not as subtle as something based on counts, but it's simple, and in practice, for all sorts of uses, it works very well.

However, if you're dead set on a count, then what i'd do is create a Decorator which wraps a strategy and keeps a count, and which can be compared with other such objects. Code is the easiest explanation:

public class ScoredStrategy implements Strategy, Comparable<ScoredStrategy> {
    private final Strategy delegate;
    private float score;

    public ScoredStrategy(Strategy delegate) {
        this.delegate = delegate;
    }

    public boolean attempt() {
        boolean success = delegate.attempt();
        score = (score * 0.9f) + (success ? 1 : -1);
        return success;
    }

    public int compareTo(ScoredStrategy that) {
        return -Float.compare(this.score, that.score);
    }
}

In the main object, take your actual strategies, and wrap each in a ScoredStrategy. Put those in a list. When you need a strategy, work over the list, calling each strategy until you hit one that works. Then, simply sort the list. The strategies will then be in order, from best to worst.

like image 44
Tom Anderson Avatar answered Nov 13 '22 10:11

Tom Anderson