In this article, we will understand about Strategy pattern. Let’s get started.


Table of contents


Given Problem

Normally, when we have a set of algorithms that we need to perform in the Context class. They will be acted that depends on a condition in switch or if-else statement.

When the amount of values of a condition in switch or if-else statement increases, it makes our code very long. On the other hand, algorithms are often extended, optimized, and replaced during development and reuse, so our code will be illegal the Single Responsibility Principle of SOLID because with switch statement we have multiple reasons to change.

The changes always make Context class more complex, our code do not reuse for other situations.

At the moment, the Context class is coupling with particular algorithm at compile-time, and makes it impossible to change an algorithm later independently from the class. Because we know that some specific algorithms in Context class, at run-time, we do not exchange to the other algorithm by mocking into our code.

So, we have some problems:

  • How can a class be configured with an algorithm at run-time instead of implementing an algorithm directly?
  • How can an alogrithm be selected an exchanged at run-time?
  • We can be difficult to test, because we need to cover all execution paths, and each condition require us to write at least one more test. Then, when we need to modify some algorithms, we need to test all algorithms again.
  • By using if-else or switch statement, all of the implementations are tied to that implementation, making them harder to change in the future.


Solution of Strategy Pattern

To solve the above problems, we will do some following steps:

  • Defines separate Strategy object.

    • For all supported algorithms, define a common interface - Strategy for performing an algorithm.

    • Define classes - Strategy1, Strategy2, … that implements the Strategy interface (encapsulate the algorithm).

    • This enables compile-time flexibility (via inheritance).

      New algorithm can be added and existing ones can be changed independently by defining new subclasses.

  • A Context class delegates responsibility for performing an algorithm to a Strategy object –> strategy.algorithm();

    • This enables run-time flexibility (via object composition).

      A class can be configured with a Strategy object, which it uses to perform an algorithm, and the Strategy object can be exchanged dynamically.


When to use

  • When we want to choose algorithm at run-time.


Benefits & Drawback

  1. Benefits

    • Reduce the cyclomatic complexity when we do not use if-else or switch statement. Then it makes no branching code.

    • Improve encapsulation.

    • Swap behavior at runtime.

    • Open-Closed Principle is respected because a new algorithm simply means adding new classes without touching exsting ones.

    • Makes our code testable, maintainable, reusable.

  2. Drawbacks

    • It makes more complicated desing (more classes).


Code C++ / Java

To refer this pattern’s code, we can read this link.


Application & Examples

  • Refactoring if-else or switch statement in our code.
  • Use with sorting.
  • Layout Managers in UI toolkits
  • Appenders, Layouts, and Filters in Log4Net and Log4j.
  • In Java 8, we can easily apply strategy pattern with lambdas.

    Each strategy implements a functional interface. Container methods take lambdas as arguments.


Wrapping up

  • The key idea of this pattern is to implement algorithms in a separate inheritance hierarchy, so that we can vary independently.

  • The strategy pattern defines a family of algorithms, encapsulating each one, and makes them interchangeable.


Thanks for your reading.


Refer:

https://www.martinfowler.com/ieeeSoftware/protectedVariation.pdf

https://softwareengineering.stackexchange.com/questions/302612/advantages-of-strategy-pattern

https://en.wikipedia.org/wiki/Cyclomatic_complexity

https://blog.bitsrc.io/keep-it-simple-with-the-strategy-design-pattern-c36a14c985e9