Click here to Skip to main content
15,868,141 members
Articles / Programming Languages / C#

Strategy Pattern Primer (Layman to Laymen)

Rate me:
Please Sign up or sign in to vote.
4.94/5 (66 votes)
19 Mar 2010CPOL7 min read 55.9K   264   55   24
This article takes a scenario based approach to make the reader understand this pattern.

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.

image001.png

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.

VitalsSimple.jpg

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:

vitalOld.jpg

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.

IBsaCalculator.jpg

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.

Boyd_BSA_Calculator.jpg

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:

VitalSigns_New.jpg

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.

Dubios.jpg

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.

FormulaChoice.jpg

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

InstantiatingFormula.jpg

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:

IBsaCalculator.jpg

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.

About this Article

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.

About the Code Provided

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Pakistan Pakistan
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
PraiseGood Work Pin
shieldguy15-Jun-16 2:11
shieldguy15-Jun-16 2:11 
GeneralMy vote of 5 Pin
ShreejayNair22-Apr-13 6:53
ShreejayNair22-Apr-13 6:53 
GeneralMy vote of 5 Pin
Kanasz Robert6-Nov-12 0:10
professionalKanasz Robert6-Nov-12 0:10 
QuestionGreat, great, atricle Pin
Petr Kohout4-Aug-12 15:34
Petr Kohout4-Aug-12 15:34 
GeneralMy vote of 5 Pin
deostroll7-May-12 20:26
deostroll7-May-12 20:26 
SuggestionUse Strategy Pattern it self instead of switch case Pin
delimavi9-Jan-12 23:58
delimavi9-Jan-12 23:58 
GeneralMy vote of 4 Pin
suhasis22-Nov-10 20:19
suhasis22-Nov-10 20:19 
GeneralMy vote of 5 Pin
Member 278176622-Jul-10 8:35
Member 278176622-Jul-10 8:35 
GeneralRe: My vote of 5 Pin
Syed Saqib Ali Tipu31-Jul-10 21:01
Syed Saqib Ali Tipu31-Jul-10 21:01 
Generalhelpful article Pin
vikramsagar19-May-10 3:27
vikramsagar19-May-10 3:27 
GeneralRe: helpful article Pin
Syed Saqib Ali Tipu21-May-10 22:30
Syed Saqib Ali Tipu21-May-10 22:30 
GeneralStrategy pattern primer Pin
geoyar27-Mar-10 16:00
professionalgeoyar27-Mar-10 16:00 
i think you oversimplified the problem.
Actually it is better to register your bsd functions. So you will need functors with embedded registration functions, and some entity to keep container of these functors (static functions returning new Functor), and some other stuff.
I understand that your purpose was to communicate the idea of the strategy pattern, but laymen should be warned about the real world.
But I like the article: clear and straight.
geoyar

GeneralRe: Strategy pattern primer [modified] Pin
Syed Saqib Ali Tipu31-Mar-10 20:43
Syed Saqib Ali Tipu31-Mar-10 20:43 
GeneralGreat article Pin
Muhammad Asim Hashmi25-Mar-10 3:00
Muhammad Asim Hashmi25-Mar-10 3:00 
GeneralGood article Pin
CurtainDog23-Mar-10 13:46
CurtainDog23-Mar-10 13:46 
GeneralVery easy to understand Pin
Mansoor Jaffery19-Mar-10 8:03
Mansoor Jaffery19-Mar-10 8:03 
QuestionEvent handler--case statement? Pin
supercat919-Mar-10 5:12
supercat919-Mar-10 5:12 
AnswerThanks for the feedback but I am afraid you missed the point [modified] Pin
Syed Saqib Ali Tipu19-Mar-10 7:47
Syed Saqib Ali Tipu19-Mar-10 7:47 
GeneralMy vote of 2 Pin
Sacha Barber19-Mar-10 5:01
Sacha Barber19-Mar-10 5:01 
GeneralRe: My vote of 2 Pin
Syed Saqib Ali Tipu19-Mar-10 18:01
Syed Saqib Ali Tipu19-Mar-10 18:01 
GeneralRe: My vote of 2 Pin
Saurabh_Saxena21-May-10 4:39
Saurabh_Saxena21-May-10 4:39 
GeneralRe: My vote of 2 Pin
Saurabh_Saxena21-May-10 4:39
Saurabh_Saxena21-May-10 4:39 
GeneralRe: My vote of 2 Pin
Syed Saqib Ali Tipu21-May-10 22:37
Syed Saqib Ali Tipu21-May-10 22:37 
GeneralRe: My vote of 2 Pin
abdurahman ibn hattab17-May-12 14:12
abdurahman ibn hattab17-May-12 14:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.