Strategy Pattern

Strategy Pattern is a behavioral design patter.

According to wikipedia:

It enables selecting an algorithm at runtime. It

  • defines a family of algorithms
  • encapsulates each algorithm
  • makes the algorithms interchangeable within that family
  • lets the algorithm vary independently from clients that use it

I will walk through some examples of strategy pattern in this post, hoping that it will give you and myself some insight of this pattern.

A simple example

As the UML diagram above, there is an interface called Strategy and it is implemented by ConcreteStrategy1 and ConcreteStrategy2 which encapsulate different algorithms.

The class Context is a composition. It has an object of Strategy. And its method operate() depends on the specific algorithm strategy.doSomething().

1
2
3
4
5
6
7
8
9
10
11
public class Context {
private Strategy strategy;

public Context(Strategy strategy) {
this.strategy = strategy;
}

public void operate() {
strategy.doSomething();
}
}

By using contructor injection, the context object is initialized with a strategy. And by using setter injection, the client code can change its strategy at runtime.

1
2
3
4
Context context = new Context(new ConcreteStrategy1());
context.operate(); // use the algorithm implemented by ConcreteStrategy1
context.setStrategy(new ConcreteStrategy2());
context.operate(); // use the algorithm implemented by ConcreteStrategy2

By favoring composition over inheritance, strategy pattern decouples the implementation of algorithms and the context where the algorithms are executed. And it is more flexible than having the algorithm implemented within Context, because it not only allows the clients to choose a specific algorithm but also lets them implement new algorithms.

An argument

Some say that the sorting method provided by Java Collections is an example of strategy pattern, but others argue that it is merely an example of a simple polymorphic substitution.
Let’s look at the code first.
This is the implementation of Collections.sort(). It takes an implementation of Comparator as a parameter. Comparator is an interface for comparing items.

1
2
3
4
5
public class Collections {
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
}

To call this method sort(), the client must implement the interface Comparator and pass the object of the implementation class to the method.

1
2
3
4
5
Collections.sort(myList, new Comparator<ListType> {
@Override public int compare(ListType o1, ListType o2) {
return o2.val - o1.val;
}
})

Those who argue that it uses strategy pattern give the following reasons:

  • There is an interface Comparator, and the clients can encapsulate their own algorithms of comparison by implementing the interface.
  • The algorithms are independent from the sorting method.
  • The clients can choose any algorithm for the sorting method at runtime.
  • The method sort() is the context.

If we look at the definition of strategy pattern, I would say that the arguements are valid and Collections.sort() does use strategy pattern.

Now let’s look at those who disagree. They argue that the comparator algorithms are not the compositors of the Collections class. They insist that a context with has-a relationship is another important factor in strategy patter. Why does this matter?

This is my own theory. Suppose Collections is implemented in this way:

1
2
3
4
5
6
7
8
9
10
public class Collections {
private Comparator comparator;

Collections(Comparator comparator) {
this.comparator = comparator;
}

public <T> void sort(List<T> list) { // ... }
public <T> void binarySearch(List<T> list) { // ... }
}

When we create an object of Collections, it has choosen one comparator algorithm for all of its methods. The comparator algorithm is a part of Collections and it is the base stone of all the methods that depend on it, although the algorithm can be changed later on. This is different from making an algorithm part of a method. Why is the class Collections not implemented in the above way? It is because the Collections class is a utility class and it is not flexible to have only one comparator for all the utility methods.

In conclusion, I would say Collections.sort() is not an example of strategy pattern.

A not-that-simple example

This example shows more insight of why strategy pattern favors composition over inheritance.

Suppose there is a WordProcessor which handles words from different sources. As show in the UML diagram below, WordProcessor1 and WordProcess2 are two different types of processors, and they adopt different implementation of decompress() and format(), WordProcessor3 inherits WordProcessor2 but it implements format() in the same way as WordProcessor1.

So inheritance couples the objects and its behaviors and makes it inflexible to create other types of objects with different combinations of behaviors, and it is impossible to reuse code. In this case, a better solution is to use composition over inherirtance, that is, let the behaviors be the compositors of the object (as explained in the UML diagram below).

More examples

Let’s check out some real examples.

i. Splitter in guava library

Splitter is a utility of extracting substrings from an inputing string based on a separator. Here is an example of how it is used:

1
2
3
// Splitter.on() is a public static method, and it returns an instance of Splitter
// Note that instantiation through constructor is impossible since it is private
Iterable<String> substrings = Splitter.on(',').split("dek,fool,yog");

This separator can be a single character, a fixed string, a regular expression, or a CharMatcher instance. For each type of separator, a Splitter instance is created by injecting a specific Strategy which implements an algorithm of finding the starting index and ending index of the next separator. It looks like a factory that manufactures different products using different strategies.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public final class Splitter {
private final Strategy strategy;
private Splitter(Strategy strategy, ...) { // ... }

public static Splitter on(final CharMatcher separatorMatcher) {
return new Splitter(new Strategy() {
@Override public SplittingIterator iterator(Splitter splitter, final CharSequence toSplit) {
// ...
}
});
}

public static Splitter on(final String separator) {
return new Splitter(new Strategy() {
@Override public SplittingIterator iterator(Splitter splitter, CharSequence toSplit) {
// ...
}
});
}

public static Splitter on(final Pattern separatorPattern) {
return new Splitter(new Strategy() {
@Override public SplittingIterator iterator(final Splitter splitter, CharSequence toSplit) {
// ...
}
}
});

private interface Strategy {
Iterator<String> iterator(Splitter splitter, CharSequence toSplit);
}
}
}

The advantage of applying strategy pattern here, in my opinion, is making the code reusable, by implementing the logic of splitting a string in a generic way so that it can be re-used in any case despite what kind of the separator is, and having the specific algorithms of handing different kinds of separators encapsulted in Strategy.

Note that the interface Strategy is also declared as private, so it is not open to the clients to implement their strategies.

ii. Java API: java.util.zip.CheckedInputStream

CheckedInputStream maintains a checksum of the data being read. Strategy pattern is applied here to provide two way to computate checksum, as shown in the UML below.

iii. The View-Controller relationship in Smalltalk MVC

Let’s define MVC first (quoted from the book of Gang of Four):

The Model is the application object, the View is its screen presentation, and the Controller defines the way the user interface reacts to user input.

According to the definition, the Controller encapsulates the response mechanism, and each Controller subclass can be taken as a particular strategy; the View is the context, to change how it is reacted to user input, it just simply replaces the Controller object with a different kind of controller without modifying the View.

P.S. I don’t think spring mvc is implemented in this way, but I will dig more about it later.

Strategy pattern and dependency injection

Dependency injection is the key of implementing strategy pattern. Dependency injection passes an object which can be used to a dependent object which will use it, so that the dependent object doesn’t have to look for its dependency, and hence the dependent object and its dependency are decoupled.
In strategy pattern, dependency injection is used to pass different strategies to the context.

References:

1 Wikipedia: Strategy Patter
2 What design pattern does Collection.sort use
3 Wikipedia - Dependency Injection
4 Guava | Splitter