Should Strategy Objects Have State?

The previous post on saving memory with Strategy objects was around using singleton instances of them rather than creating a new one every time. This has advantages:

  • Lower overhead of object creation
  • Maximum of 1 of each of the strategies in memory at any given time

It has the minor disadvantage of

  • Possible concurrency issues – though this shouldn’t be a problem if it’s truly stateless
  • Over time, exactly 1 of each strategy objects will be permanently in memory, which shouldn’t be a problem if it’s stateless

So the question comes back – should strategy objects have state?

There are two answers to this boolean question. But there are two answers to all booleans. The specific answers are:

  • The Strategy Pattern is intended to be stateless
  • A functioning object may, by definition, be stateful, depending on how it is coded

Stateless Strategy Pattern

In simple terms the strategy pattern has this signature:

public interface IStrategy
{
   public void PerformOperationOn(Context context);
}

This is the stereotype. You would normally name your strategy and context classes based on the problem domain. For example IParsingStrategy and DocumentContext might be a parser that operates over a document container to read something from the document and write something else back in.

The very existence of a strategy object – say an HTMLElementFinderStrategy – is to represent the chosen algorithm, not represent program data, or the state of the algorithms. Algorithms are, by definition, stateless. To execute they may have temporary variables, that’s not state, even though some classes use internal members as temporary variables.

So in summary, you could argue that most strategies are inherently stateless.

When objects are not just code

Inheritance is great, but in some situations it’s an antipattern. When you have lots of subclasses of an interface or base class, and each subclass has a different implementation, then it’s great. It stops being great when the implementations start having a lot in common with each other. Perhaps this can be dealt with as an inheritance hierarchy, but perhaps it can’t. Imagine an example of a paragraph formatting strategy. You give it a string and it outputs the paragraph in HTML, depending on the format of the paragraph.

public interface IHTMLFormattingStrategy
{
   public string AsHTML(string input);
}

In this case the context is simple and it’s a strategy that returns its result. That’s fine.

So now think of the sorts of paragraph formats we might implement. Perhaps a BoldParagrah or an ItalicsParagraph etc. The more variants, the more the number of possible permutations? How would you, for example, make a BoldItalicsParagraph? This is where inheritance fails – it’s too linear a way of composing the implementations into a single set of functionality.

So our design patterns library provides us patterns for composing a complex object out of chains of objects. The Decorator pattern is the obvious fit here.

So to conclude, you might, to meet the needs of the input, select a strategy object that is, itself, composed of a series of stateless objects, woven together to make an entity which has the desired behaviour, formed out of object composition, rather than static code. These objects, representing all possible permutations possible, might be difficult to store and kind of have an internal state – the dynamically wired-up modules – and need to be memory managed. In this case, though, they’re still almost stateless, and are pretty small. Sure they may stay in memory, but only so long as they’re used, and perhaps the code that needs the strategy should only hold onto a strong reference to it for as long as it is needed.

Advertisements

4 comments

  1. The question is from myPOV not formulated in the right way, it should be …
    Is there a valid example, for a strategy pattern, where the strategy must have “state” and the singelton implementation fails ?

    Take a look at the following example IRandom with the only method Next, here you can easily find many small strategies for the implementation like “Normal Distribution”, “Logarithmic Distribution” or “Compound Poisson Distribution” and many more, the singelton implementation will fail not even in a “multi threaded context”, it just will fail, when you use the strategy a second time.

    So one of the precondition for using the “Singelton” in a “Strategy” object must be, there is ever never a “Strategy”, which has state….

    On the other side, the implementation we are discussing is from GOF POV not the correct implementation of the strategy pattern, because in the original design pattern always an object is passed to a context….

    So I would name this pattern “Strategy Finder” or “Strategy Provider” and then from my feeling the decision, if the strategy is provided to the application as a Singelton or not, should/must be in the responsiblity of the “Strategy Provider”

    • As with all patterns, there are always exceptions. I could imagine a random number generator that needs a local seed and one which uses a global seed. As you described it, you would have a local seed and use a stateful strategy that is provided by a strategy selector that is also a factory.

      No problem.

      The Strategy and State patterns are related and the possibility to use Singleton instances of them applies when relevant. For the State pattern, I think it applies more.

      This is the thing about patterns. There are no rules that apply to all situations. Experience suggests to use occams razor. Keep it simple and don’t have too many objects.

  2. Yeah, I agree keep it simple 🙂

    I have just the fear, that also the uneperienced uses occams razor with the result ->

    “Strategies should be always implemented as a Singelton” …

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s