Fri 18 Nov 2011
Design Patterns: Strategy Pattern
The Strategy Pattern is a new favorite design pattern of mine. Probably because it has made my life substantially easier on a bunch of occasions. You can use it for situations when you’d like to group together a family of algorithms and interchangeably drop them into other code units (e.g. objects) at run-time. These strategies are readily reusable, composable and mixed in to your code.
Traditional implementations of the Strategy Pattern implement it with function pointers or first-class functions. These are stored away and later selected according to some given set of requirements. For example, say I write some awesome code for binding Subscription domain objects with incoming HTTP request data in a flexible manner. I can label my binding service as a strategy (suitable) for Subscription objects and they’ll automatically pick it up for binding.
In the Rally code base we implemented the Strategy Pattern using Java annotations. Our framework uses reflection to get classes annotated @StrategyFor and stores them in a Map. The association between consumers and strategies is based on type. Since types are hierarchical in Java we can write strategies for more than just a single class: we can annotate as a @StrategyFor some parent class and cover an entire sub-hierarchy.
Here’s a code example. Let’s say toward the end of some transaction we want all Artifacts to be processed and have their custom attributes set. So:
@StrategyFor(Artifact.class)
public class ArtifactPostProcessor implements DomainObjectPostProcessor {
@Override
public void process(DomainObject domainObject, Map arguments) {
Artifact artifact = (Artifact)domainObject;
artifact.setAllCustomAttributeValues();
}
}
Ok, so now you’re thinking, if a family of objects needs a given behavior why not just create some interface and have them all implement it? Sometimes that is too tightly coupled: changing the interface means having to change every single implementing object.
The Strategy Pattern is an alternative that encourages building objects by composition over inheritance. Using composition means you can change the description of the superclass (what would be the Strategy class) without breaking the subsclasses.
Neat, huh?
