Click here to Skip to main content
15,889,335 members
Articles / Patterns

Design Patterns: Strategy

Rate me:
Please Sign up or sign in to vote.
4.57/5 (14 votes)
12 Oct 2015CPOL2 min read 15.1K   8   16
Design Patterns: Strategy

Often times, we need to change some algorithm with another without changing the client code that's consuming it. In this post, I want to show a use case I came across and utilized Strategy pattern.

What Is It?

Here's the official definition of the pattern from GoF book:

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Use Case: Get External IP Address

In an application I was working on, I needed to get the external IP address of the computer the application is running on. There are various ways to achieve that. This looked like a good opportunity to use the Strategy pattern as I wanted to be able to switch between the different methods easily.

Implementation

The interface is quite simple:

C#
public interface IIpCheckStrategy
{
    string GetExternalIp();
}

Some services return their data in JSON format, some have extra text in it. But encapsulating the algorithms in their own classes this way, the client code doesn't have to worry about parsing these various return values. It's handled in each class. If one service changes its output and breaks the implementation, I can recover just by changing the code instantiates the class.

The concrete implementations of the interface are below. They implement the IIpCheckStrategy and are responsible for getting the data and return parsed IP address as string.

AWS IP Checker:

C#
public class AwsIPCheckStrategy : IIpCheckStrategy
{
    public string GetExternalIp()
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri("http://checkip.amazonaws.com/");
            string result = client.GetStringAsync("").Result;
            return result.TrimEnd('\n');
        }
    }
}

DynDns IP Checker:

C#
public class DynDnsIPCheckStrategy : IIpCheckStrategy
{
    public string GetExternalIp()
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri("http://checkip.dyndns.org/");
            HttpResponseMessage response = client.GetAsync("").Result;
            return HelperMethods.ExtractIPAddress(response.Content.ReadAsStringAsync().Result);
        }
    }
}

Custom IP Checker:

C#
public class CustomIpCheckStrategy : IIpCheckStrategy
{
    public string GetExternalIp()
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri("http://check-ip.herokuapp.com/");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add
            (new MediaTypeWithQualityHeaderValue("application/json"));

            HttpResponseMessage response = client.GetAsync("").Result;
            string json = response.Content.ReadAsStringAsync().Result;
            dynamic ip = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
            string result = ip.ipAddress;
            return result;
        }
    }
}

Choosing the Algorithm

The consumer of the algorithm can pick any class that implements IIpCheckStrategy and switch between them. For example:

C#
class StrategyClient1
{
    public void Execute()
    {
        IIpCheckStrategy ipChecker;

        ipChecker = new DynDnsIPCheckStrategy();
        Console.WriteLine(ipChecker.GetExternalIp());

        ipChecker = new AwsIPCheckStrategy();
        Console.WriteLine(ipChecker.GetExternalIp());

        ipChecker = new CustomIpCheckStrategy();
        Console.WriteLine(ipChecker.GetExternalIp());

        Console.ReadKey();
    }
}

Also, the class name to be used can be stored in the configuration in some cases so that it can be changed at runtime without recompiling the application. For instance:

C#
class StrategyClient2
{
    public void Execute()
    {
        string ipcheckerTypeName = ConfigurationManager.AppSettings["IPChecker"];

        IIpCheckStrategy ipchecker = 
        Assembly.GetExecutingAssembly().CreateInstance(ipcheckerTypeName) as IIpCheckStrategy;

        Console.WriteLine(ipchecker.GetExternalIp());
    }
}

and the appSettings in the configuration would look like this:

C#
<appsettings>
        <add key="IPChecker" value="Strategy.AwsIPCheckStrategy">
</add></appsettings>

Resources

This article was originally posted at http://volkanpaksoy.com

License

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



Comments and Discussions

 
GeneralNice to see others using Activator.CreateInstance Pin
rhyous13-Oct-15 13:09
rhyous13-Oct-15 13:09 
GeneralRe: Nice to see others using Activator.CreateInstance Pin
User 955792413-Oct-15 13:14
User 955792413-Oct-15 13:14 
GeneralMy vote of 5 Pin
dmjm-h13-Oct-15 12:11
dmjm-h13-Oct-15 12:11 
GeneralRe: My vote of 5 Pin
User 955792413-Oct-15 12:30
User 955792413-Oct-15 12:30 
General[My vote of 2] Bad Formatting of code!!!! Pin
Praveen Raghuvanshi12-Oct-15 18:11
professionalPraveen Raghuvanshi12-Oct-15 18:11 
GeneralRe: [My vote of 2] Bad Formatting of code!!!! Pin
User 955792412-Oct-15 20:24
User 955792412-Oct-15 20:24 
GeneralRe: [My vote of 2] Bad Formatting of code!!!! Pin
Marco Bertschi13-Oct-15 3:10
protectorMarco Bertschi13-Oct-15 3:10 
GeneralRe: [My vote of 2] Bad Formatting of code!!!! Pin
Sean Ewington13-Oct-15 6:19
staffSean Ewington13-Oct-15 6:19 
GeneralRe: [My vote of 2] Bad Formatting of code!!!! Pin
Tomas Takac12-Oct-15 21:51
Tomas Takac12-Oct-15 21:51 
GeneralRe: [My vote of 2] Bad Formatting of code!!!! Pin
Marco Bertschi13-Oct-15 2:59
protectorMarco Bertschi13-Oct-15 2:59 
GeneralRe: [My vote of 2] Bad Formatting of code!!!! Pin
User 955792413-Oct-15 3:04
User 955792413-Oct-15 3:04 
GeneralRe: [My vote of 2] Bad Formatting of code!!!! Pin
Marco Bertschi13-Oct-15 3:08
protectorMarco Bertschi13-Oct-15 3:08 
GeneralRe: [My vote of 2] Bad Formatting of code!!!! Pin
User 955792413-Oct-15 3:10
User 955792413-Oct-15 3:10 
GeneralRe: [My vote of 2] Bad Formatting of code!!!! Pin
Marco Bertschi13-Oct-15 3:11
protectorMarco Bertschi13-Oct-15 3:11 
GeneralRe: [My vote of 2] Bad Formatting of code!!!! Pin
SteveHolle13-Oct-15 4:15
SteveHolle13-Oct-15 4:15 
GeneralRe: [My vote of 2] Bad Formatting of code!!!! Pin
Marco Bertschi13-Oct-15 3:09
protectorMarco Bertschi13-Oct-15 3:09 

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.