Composites, decorators, and strategies

Recently I have been interviewing for different positions and there is one that requires completing a coding challenge. To prevent disclosing anything specific about the company or the position, I will reduce the problem domain to something that fits in a blog post.

It is a simple domain with a well-defined state transformation f:

f: (State, UserInput) -> State

This is just simply saying given a State and UserInput tuple, return a new State. I would have modelled it with this function signature if I were programming in F♯ but unfortunately I am required to use C♯ :(

There are really two constraints when I was implementing this:

  1. The resulting design and implementation must be SOLID. Well this is not quite a surprise, isn’t it? I am submitting my solution to impress my future employer!
  2. Do not forget constraint number one

Strategy

First thing to notice here is the function f is some form of the strategy pattern because you can implement any functions with the same signature as f and let your DI container choose the correct strategy to execute at runtime to get an updated State object. Here I have implemented a State class, a UserInput class, and two concrete implementations of IStrategy :

It is easy to inject these IStrategy instances to consumers that require them:

The composition root (using Simple Injector) as an example:

Notice a few things here:

  1. The strategies are registered as singletons because those concrete implementations are pure (i.e. new States are determined solely by GetNewState arguments)
  2. You can only use one of the concrete strategies only due to the fact that MyService only requires one instance of IStrategy only. That limits re-usability: what if I want to apply both add and multiply strategies?

Composite

This brings us to the next topic, the composite pattern. In order to follow the open-closed principle, how can we not modify MyService but allow both AdditionalStrategy and MultiplyStrategy be applied?

The answer is making use of a composite IStrategy:

The beauty of this design is that CompositeStrategy is able to wrap AddStrategy and MultiplyStrategy but still be able to present to its consumer as an instance of IStrategy. The implication is that CompositeStrategy can be injected into MyService without modifying the its implementation.

Also, note that I named the local variable accumulator on purpose. Astute readers may find that this looks awfully similar to a fold (aka Aggregate in LINQ). That’s why the more functional way to write this is by eliminating the foreach loop altogether:

Decorator

OK, so we have implemented a composite to Add and Multiply. But suppose I also need to persist the new State. In order to write SOLID code, persistence should not affect how Add and Multiply strategies are implemented, but how can be connect the dots if we want to do the following:

AddStrategy -> MultiplyStrategy -> Persist the new state after add and multiply

The answer is to implement a decorator that wraps an internal IStrategy :

Any competent DI container should be able to wire up these IStrategy instances correctly and present them as CompositeStrategy to MyService correctly, and the resulting object graph should look something like this:

new CompositeStrategy(new[]
{
new AddStrategy(),
new PersistanceStrategy(
new FileStateRepository(), // or DbStateRepository
new MultiplicationStrategy())
};

I hope this short article explained the strategy, composite, and decorator patterns concisely in the context of a small domain problem.

Show your support

Clapping shows how much you appreciated Rex Ng’s story.