Advantages of Using the Strategy Pattern in Design

designdesign-patternsobject-oriented-designpatterns-and-practicesstrategy

Why is it beneficial to use the strategy pattern if you can just write your code in if/then cases?

For example: I have a TaxPayer class, and one of its methods calculates the taxes using different algorithms. So why can't it have if/then cases and figure out what algorithm to use in that method, instead of using the strategy pattern? Also, why can't you just implement a separate method for each algorithm in the TaxPayer class?

Also, what does it mean for the algorithm to change at runtime?

Best Answer

For one thing, big clumps of if/else blocks are not easily testable. Each new "branch" adds another execution path and thus increases the cyclomatic complexity. If you want to test your code thoroughly, you'd have to cover all execution paths, and each condition would require you to write at least one more test (assuming you write small, focused tests). On the other hand, classes which implement strategies typically expose just 1 public method, which is easy to test.

So, with nested if/else you'll end up with many tests for a single part of your code, while with Strategy you'll have few tests for each of multiple simpler strategies. With the latter, it's easy to have better coverage, because it's harder to miss execution paths.

As for extensibility, imagine you are writing a framework, where users are supposed to be able to inject their own behavior. For example, you want to create some kind of tax calculations framework, and want to support tax systems of different countries. Instead of implementing all of them, you just want to give framework users a chance to provide an implementation of how to calculate some particular taxes.

Here is the strategy pattern:

  • You define an interface, e.g. TaxCalculation, and your framework accepts instances of this type to calculate taxes
  • A user of the framework creates a class which implements this interface and passes it to your framework, thus providing a way to perform some part of calculations

You cannot do the same with if/else, because that would require changing the code of the framework, in which case it would not be a framework anymore. Since frameworks are often distributed in compiled form, this may be the only option.

Still, even if you just write some regular code, Strategy is beneficial because it makes your intents clearer. It says "this logic is pluggable and conditional", i.e. there can be multiple implementations which may vary depending on user actions, configuration, or even platform.

Using the Strategy pattern may improve readability because, while a class which implements some particular strategy typically should have a descriptive name, e.g. USAIncomeTaxCalculator, if/else blocks are "nameless", in best cases just commented, and comments can lie. Also, fr my personal taste, just having more that 3 if/else blocks in a row is not readable, and it gets pretty bad with nested blocks.

The Open/Closed principle is also very relevant, because, as I described in the example above, Strategy allows you to extend a logic in some parts of your code ("open for extension") without rewriting those parts ("closed for modification").

Related Topic