Java Design Patterns – Strategy with Fields Acceptability

design-patternsjava

Both here on stack overflow and on Java Effective it is suggested that strategy design patterns should be stateless. In fact in the book it is also suggested to make each strategy object a singleton.

The problem I have is that some strategies I envision for my program need states/fields. Either because they are path-dependent in their behavior or because I want them heterogeneous (a statistical distribution of similar strategies, if you prefer).
This forces me to break both Java Effective suggestions: I instantiate a new strategy for each user class AND each of these strategies contain its own fields.
Is that very bad? Should it be done differently?

It was suggested to me to keep the fields that make the strategy heterogeneous in the class that uses it and then pass it as an argument. I find that very anti-oo. Those fields don't belong to the user class. In fact, if that class uses another strategy it might not need those fields at all. That seems to run against the reason I am using the strategy pattern in the first place.
Mostly I am just very confused


I make a simple example here. Imagine you have a class Gambler, which represents somebody making bets on horses. Now this class will require a strategy predictStrategy that will work something like this:

interface predictStrategy{
    public Horse predictWinningHorse(HorseRace r);
}

Now, I can have many implementations where the strategy is to choose at random, or pick the white horse or whatever. That's easy.
Imagine though that I implement a strategy that looks at past predictions and somewhat "learns" from its past mistakes. Clearly each strategy will have to have its own memory on which to learn. I might have to add one more method to the interface (or make an extension)

interface predictStrategy{
    public Horse predictWinningHorse(HorseRace r);

    public void addObservation(HorseRace r, Horse oldPrediction, Horse actualWinner);
}

So that the Gambler class calls "strategy.addObservation(…)" at the end of each race to improve its predictive power.
Can this be really be done with a stateless strategy object? It seems impossible to me.

Best Answer

I would argue that each instance should remain stateless once it is constructed, i.e., it should not maintain extra state across invocations that changes based on the parameters. A classic example is a tax calculator.

interface TaxCalculator {
    /**
     * Calculates the tax for the given purchase price and shipping charges.
     * All values are in pennies to avoid rounding.
     *
     * @param subtotal total price of all items ordered
     * @param shipping cost of shipping the order
     * @return calculated tax
     */
    int calculate(int subtotal, int shipping);
}

class NoTax implements TaxCalculator {
    public int calculate(int subtotal, int shipping) {
        return 0;
    }
}

class FixedPercentOfSubtotal implements TaxCalculator {
    private final int ratePercent;

    public FixedPercentOfSubtotal(int ratePercent) {
        this.ratePercent = ratePercent;
    }

    public int calculate(int subtotal, int shipping) {
        return subtotal * ratePercent / 100;
    }
}

While FixedPercentOfSubtotal has a member (state), it's provided at construction time and never changes. You could store one instance per state, making them quasi-singletons.

Update

Neither the Wikipedia article nor this Strategy Pattern page make any stipulation that implementations should not maintain state across calls. It's less common because strategies are designed to be interchangeable and pluggable at runtime, but I wouldn't rule it out.

However, that you needed to add a new method to enable that one strategy implementation is a red flag. Other implementations may not need it. Will you define it in the interface anyway? It may make more sense to have the historical-tracking strategy implement RaceListener and add it to the race track instance. This would allow it to be shared among multiple users as a singleton.

Related Topic