Your sample is a pretty short one that supports the perceiption that using a Strategy is not too much value over the separate-method-approach. However, in a more complex situation the DoOperation
method will be much more complex und call the Strategy only at specific points in its algorithm.
In this case you might want to test the Context algorithm (in your case the Calculator
class) separately without mixing the tests with specific implementations in the methods. The pattern enables you to separate these algorithms and test them separately. If a test fails, you can easily identify the block of code that led to the failure. If you follow the separate-method-approach, the probability is high that the methods share some common (or worse: duplicate) code that is located in the Context in the pattern. In this case, if you receive a test failure, it is harder to identify the part of code that leads to the failure.
In addition, implementing a Strategy supports the Open-Closed-principle as the Context class does not need to be changed if you add another Strategy. Also the existing Strategies remain unchanged.
Another advantage of the Strategy pattern is that you can change the Strategy at run time. Typically, the current Strategy is published as a property of the Context. If for some reason you decide that you need to change the behavior of the Context, you simply create the new Strategy and assign it to the property of the Context. If you follow the separate-method-approach, you decide at compile time which method you want to call. Of course you can add some if
statements to react on some conditions. If using a Strategy, you can assign another Strategy to the Context and do not need to use if
statements. This reduces the number of cases you need to test.
Which approach suits a specific situation better depends on the situation, but there are definitely strong reasons to implement a Strategy.