11,578,524 members (60,669 online)

Strategy Pattern Primer (Layman to Laymen)

, 19 Mar 2010 CPOL 27.9K 175 52
 Rate this:

Introduction

A lot has been written on this topic, and some pretty eloquent, then why another article. I feel most of these are too abstract for a beginner, and he/she is pretty much entangled in the definition and problem statement rather than truly comprehending the true power and possibilities of usage. This is my humble effort that is targeting not much experienced programmers rather than seasoned ones; some may get the benefit though. I will try to keep things as simple as possible. I have chosen the strategy pattern as the first pattern to write about as it’s one I come across most, and I think it’s among the most widely used design patterns. The class diagram for the strategy pattern is given below.

Definition

First a formal definition:

Strategy pattern is a technique of decoupling an algorithm from a class that is hosting it so that we can choose a particular algorithm at runtime. Our host (ie context) class doesn’t care what the concrete implementation is any more as it will deal with the abstraction.

It’s alright, if at this stage, you don’t understand even a word of it. I hope that after reading the next section, if you will read this definition again it will not only make sense, but you will also understand where to apply this pattern. However, I am presuming that the reader is well acquainted with object-oriented terms like polymorphism, inheritance, interfaces and abstract classes.

The Thought Process

Consider this scenario that you are developing a reusable Electronic Medical Record API and your current task is to implement the module that will calculate Body Surface Area (BSA) that is based on two factors, height and weight, residing in the class `VitalSigns`.

Check http://www.halls.md/body-surface-area/refs.htm for different formulae available. Now the hypothetical part. Let’s say currently only two formulae are known, Boyd and Heycock. But there are some under standardization or in the development phase. A possible modification to the `VitalSigns` is as below:

At first sight the solution seems fine, but it has one flaw, it’s not extensible. When the new formulae will be standardized, API users will need support for these in their applications. With this implementation, the only possibility you have is to add another case in the function, `CalculateBSA()`, and then recompile your API and provide them the patch. To worsen the situation, your DLL might be strongly named causing the developers to recompile everything. Or the API user will have to implement most from scratch, and they won't be getting any benefit from your API.

How nice it would be if you can somehow manage this changing functionality separate of your `VitalSigns `class and provide them as dependencies when user needs BSA Calculation. You had better provide the user some mechanism to plug their implementations through this mechanism, it will be extremely flexible. That’s where strategy pattern comes into play. It will make your solution quite extensible, and your `VitalSigns `class will need no change for new implementations.

So now we will see how strategy pattern will solve this problem. The problematic function is `CalculateBSA`. Hence we will implement it separately. First, we will implement the interface (because it is the key to extensibility, and by the end you will understand why).
So here is the interface you developed.

NOTE: Usually we pass the whole context object (`VitalSigns `instance in our case). The debate for choosing scalar values like this or whole context is pretty similar to choosing Scalar values or entity classes across different layers. I will come to this point at the end, so for now you can pretty much ignore this note .

Each formula you have will become a concrete implementation of this interface, e.g. for boyd.

Since all concrete implementations are derived from `IBsaCalculator`, all these can be treated as `IBsaCalculator `itself. To accommodate our changes, we will update our vital signs class as below:

Inside `CalculateBSA()`, we have called the `CalculateBSA(double, double)` of interface, which will obviously be called polymorphically.

What Have We Accomplished

Well this solution is pretty much extensible. Let me clarify this with an example. Suppose when you deliver your API, the very next day Dubois formula was released. Now the user does not have to wait for a new version, and can implement it in his application, by deriving from `IBsaCalculator `and then assigning it to `VitalSigns `instance’s `BsaCalculator `property. All he has to do is to give another concrete implementation of `IBsaCalculator`.

We don’t have to modify the `VitalSigns `class for new implementations and we can plug different implementations of calculators at runtime according to the requirements.

Who Will Provide the Dependency Then?

There is no such thing as absolute decoupling. Dependencies are like matter, that cannot be destroyed. Seasoned programmers just mold them to get better extendible and maintainable solutions. For example when you use frameworks like Spring, dependencies just don’t vanish in thin air. You’re mentioning them in XML files rather than hard coding in your code, and now rather than your code, the framework is providing these dependencies, making your classes decoupled from each other. The question is where should we provide our concrete implementations to `VitalSigns `class? Obviously now, the client (by client, I mean the code that is going to use all this) has to know about these concrete implementations and he is responsible for providing the required calculator. We can delegate the creation task to factory method to add another layer of abstraction, but let’s not overcomplicate things and stay with a simplistic implementation. Let me explain this point. Suppose we are displaying all available formulae in a `ComboBox`.

The event handler code for user selection will look something like this:

Here `vs `is the instance of our context class (`VitalSigns`).
So we have seen how strategy pattern has made our `VitalSigns `class extendible. We can not only plug in our own implementation, but also can provide as well as change the choice at runtime.

Another Possible Scenario

I will not spend much time on this scenario, and leave it as an exercise to the reader. Suppose you have a huge hierarchy of classes, for example, something like world famous `Vehicle `class, which has derivatives like car, truck, wagon, etc. Each derivation has many further derivations and so on. Suppose you have to override `Move()` function in most classes in this hierarchy. This will make your implementations of `Move()` cluttered across the whole hierarchy, making it very hard to maintain. So you can use the strategy pattern, and separate out the Move implementation and implement it isolatedly. Here we haven’t mainly achieved extensibility but maintainability.

Scalar Values or Context Class Itself?

In my implementation I have used scalar values, `height` and `width`:

Usually people prefer passing the whole context like `CalculateBSA(VitalSigns vs)`.

Both have their pros and cons. Scalar will make this implementation totally decoupled from `VitalSigns `which is beneficial in some cases, but if in future some formula is developed that is consuming other `VitalSigns `property, e.g. temperature additionally, it will break the implementation. Using context class will make it coupled with `VitalSigns `but will abort those sort of changes. It’s a matter of choice and depends on your requirement.

This article and the next ones in this series are by no means a comprehensive guide to design patterns. These will be mostly targeting beginners, explaining to them that design patterns are not some sort of rocket science, but just simple and elegant solution that will save you from future refactoring and maintenance. The goal is to present these patterns as simple as possible and refraining from any complex implementations. Focusing on just the pattern at hand, so a newcomer won't be confused. By the end of the series, I will try writing about how to network these patterns to create a flexible and maintainable application framework. For example, we could have created a Factory to instantiate and decouple the clients from creation of concrete implementations, but rather than presenting it here, I will try explaining it in a Factory pattern tutorial so the reader will not get confused. Your feedback will be very important, telling me the weaknesses of this article, and where I failed to clarify the concepts. Thanks.

The code I have attached with this article is developed in C# using Visual Studio 2008. However if needed, I can provide the implementation for Java using Eclipse or NetBeans, or even C++ version.

History

• 19th March, 2010: Initial post

Share

 Pakistan
No Biography provided

You may also be interested in...

 First Prev Next
 My vote of 5 Member 774896222-Apr-13 6:53 Member 7748962 22-Apr-13 6:53
 My vote of 5 Kanasz Robert6-Nov-12 0:10 Kanasz Robert 6-Nov-12 0:10
 Great, great, atricle Petr Kohout4-Aug-12 15:34 Petr Kohout 4-Aug-12 15:34
 My vote of 5 deostroll7-May-12 20:26 deostroll 7-May-12 20:26
 Use Strategy Pattern it self instead of switch case delimavi9-Jan-12 23:58 delimavi 9-Jan-12 23:58
 My vote of 4 suhasis22-Nov-10 20:19 suhasis 22-Nov-10 20:19
 My vote of 5 Member 278176622-Jul-10 8:35 Member 2781766 22-Jul-10 8:35
 Re: My vote of 5 Syed Saqib Ali Tipu31-Jul-10 21:01 Syed Saqib Ali Tipu 31-Jul-10 21:01
 helpful article vikramsagar19-May-10 3:27 vikramsagar 19-May-10 3:27
 Re: helpful article Syed Saqib Ali Tipu21-May-10 22:30 Syed Saqib Ali Tipu 21-May-10 22:30
 Strategy pattern primer geoyar27-Mar-10 16:00 geoyar 27-Mar-10 16:00
 Re: Strategy pattern primer [modified] Syed Saqib Ali Tipu31-Mar-10 20:43 Syed Saqib Ali Tipu 31-Mar-10 20:43
 Great article Member 355329025-Mar-10 3:00 Member 3553290 25-Mar-10 3:00
 Good article CurtainDog23-Mar-10 13:46 CurtainDog 23-Mar-10 13:46
 Very easy to understand Mansoor Jaffery19-Mar-10 8:03 Mansoor Jaffery 19-Mar-10 8:03
 Event handler--case statement? supercat919-Mar-10 5:12 supercat9 19-Mar-10 5:12
 Thanks for the feedback but I am afraid you missed the point [modified] ssaqibalitipu19-Mar-10 7:47 ssaqibalitipu 19-Mar-10 7:47
 My vote of 2 Sacha Barber19-Mar-10 5:01 Sacha Barber 19-Mar-10 5:01
 Re: My vote of 2 Syed Saqib Ali Tipu19-Mar-10 18:01 Syed Saqib Ali Tipu 19-Mar-10 18:01
 Re: My vote of 2 Saurabh_Saxena21-May-10 4:39 Saurabh_Saxena 21-May-10 4:39
 Re: My vote of 2 Saurabh_Saxena21-May-10 4:39 Saurabh_Saxena 21-May-10 4:39
 Re: My vote of 2 Syed Saqib Ali Tipu21-May-10 22:37 Syed Saqib Ali Tipu 21-May-10 22:37
 Re: My vote of 2 abdurahman ibn hattab17-May-12 14:12 abdurahman ibn hattab 17-May-12 14:12
 Last Visit: 31-Dec-99 18:00     Last Update: 5-Jul-15 4:48 Refresh 1