Ievgen Major

Dec 30, 2020

3 min read

Spring and Strategy Pattern

As we all know from 1994 old good Strategy pattern principle did not change, languages and frameworks did. So I will not talk about “how to implement yet another 100500 Strategy” and why it is a useful design pattern, but rather how to use specific Spring (or other IoC container) features to make it easier and efficient.

First of all, the strategy pattern is about how to organize code in a way, the exact algorithm could be selected in runtime and easily added or changed.

Implementation will require:

  1. Interface IStartegy which will be inherited by exact strategy Strategy1 and Sattegy2 etc.
  2. Strategy selector witch will define, what strategy should be used for the particular condition (could be external or internal).
  3. Processor class, that will collect all implementations and will delegate the call to exact strategy.

Approach1 switch-case

“switch — case” is used to define what strategy to call for request. I’ve used private methods to simplify code, implementation could be inner classes, lambdas of spring beans. The main problem of this approach is the “switch” statement. Also testing for this type of implementation will grow if additional items will be added.

Every time you need to implement a new strategy:

  1. add an item to enum
  2. write implementation
  3. add one more “case” statement
  4. write test

Also we can see, there is no way to add a new strategy without CaseStrategyImpl code modification.

Approach2 IoC way

Lets use Spring @Component for strategy implementation. Spring Component naming and Spring @Autowiring for strategy registration in loan processors container.

This approach removes the switch and allows you to write only strategy implementation, and spring (or other IoC container) will do all registration work for you.

From testing point of view, You will write test for exact strategy implementation

And only 1 test for processor

What is the main disadvantage of this approach? Well, the main problem here is that our enum LoanType is only semantically connected with the component name, so refactoring and correct component naming could be error-prone. Also, try not to use class names as strategy identifiers. You will expose internal implementation details and will not be able even to rename the class without external modifications.

So now every time you need to implement a new strategy:

  1. add an item to enum
  2. write implementation and name it accordingly
  3. write test for strategy, test for processor not needed

Well, we removed one implementation step and delegated it to Spring. The number of test cases also reduced. We have saved time and money. Can we do better?

Approach3. Compile time validation

Let’s introduce the interface method LoanType getCode() and implement it in every strategy.

Processor will use evaluate method and every strategy inherit it from default implementation.

As You can see processor also slightly changed. We collect strategies to EnumMap using LoanType as a key. Starting from now compiler will check everything for us. We are always writing more code to write less code)

What about tests? In my opinion whey testing exactly what they should.

Can we do better?

Approach4. Compile time validation with Generics

Well we can assume we have big application, and using strategy a lot. So it will be a good idea to have 1 abstract implementation to use everywhere. Reuse always has benefits and some generics may help, lets see.

We defined generic strategy interface, and abstract implementation for processor. Now all we need is to inherit them in our application. All registration and handling process will be provided by our strategy framework.

One small bonus

There are one more approach to register strategy.

The trick here is combination of interface and @Autowired annotation, spring will invoke method register and register strategy in registry, and then

You will be able to puzzle you colleges with one more nice strategy implementation)

All codes and tests available in repository.

Happy coding and a happy new year!