Strategy pattern with dictionary
Strategy Pattern with Dictionary
What is a good way to avoid if else statements ?
The answer is simple, use switch case statements :). But the question is what's even better ?
For this the answer that comes to my mind is Strategy pattern using dictionary. In this blog we will have a sneak into this pattern.
I would go for strategies if I have different entities who would perform the same operation in different styles. For example : If I am playing a game like football, each player in my team would have a different role (like goalkeeper, defender, striker). So to put this into OOPS, this is how we can design our application :
Strategy :
An abstract/interface which defines the strategy
Context :
The context contains the strategies defined for different players. This is the place where the strategies are registered
Concrete classes implementing strategy :
The actual strategies defined for different players are defined here.
Let's defined the strategy first :
I want to be able to define what a player is supposed to do with the football. So I create an interface as follows :
/// <summary>
/// a strategy defined for all the players in the team
/// </summary>
public interface IStrategy
{
void PlayingStrategyWith(Football ball);
}
Then I create different strategies for the different kind of players as follows :
/// <summary>
/// the job of the defender is to defend its field
/// </summary>
public class DefenderStrategy : IStrategy
{
public void PlayingStrategyWith(Football ball)
{
Console.WriteLine("defend the ball");
}
}
/// <summary>
/// the job of a forward is to striker a goal
/// </summary>
public class ForwardStrategy : IStrategy
{
public void PlayingStrategyWith(Football ball)
{
Console.WriteLine("strike the ball");
}
}
/// <summary>
/// the job of the goal keeper is to prevent goals
/// </summary>
public class GoalkeeperStrategy : IStrategy
{
public void PlayingStrategyWith(Football ball)
{
Console.WriteLine("defend goals");
}
}
Finally I create a context and register the strategies I have just defined as follows :
/// <summary>
/// context in which strategies are well defined
/// </summary>
public class FiFaContext
{
public Dictionary<PlayerType, IStrategy> Strategies = new Dictionary<PlayerType, IStrategy>();
public FiFaContext(Football ball)
{
Strategies.Add(PlayerType.Defender, new DefenderStrategy());
Strategies.Add(PlayerType.Forward, new ForwardStrategy());
Strategies.Add(PlayerType.GoalKeeper, new GoalkeeperStrategy());
}
}
As you can see in the context above I have used Dictionary to initialize my strategies. So now to trigger my strategies I just need to initialize my context.
class Program
{
static void Main(string[] args)
{
Football ball = new Football();
FiFaContext context = new FiFaContext(ball);
context.Strategies[PlayerType.GoalKeeper].PlayingStrategyWith(ball);
Console.ReadLine();
}
}
So a very simple method to write a maintainable code :). The entire source code is as follows :
using System;
using System.Collections.Generic;
namespace StrategyPattern
{
class Program
{
static void Main(string[] args)
{
Football ball = new Football();
FiFaContext context = new FiFaContext(ball);
context.Strategies[PlayerType.GoalKeeper].PlayingStrategyWith(ball);
Console.ReadLine();
}
}
/// <summary>
/// context in which strategies are well defined
/// </summary>
public class FiFaContext
{
public Dictionary<PlayerType, IStrategy> Strategies = new Dictionary<PlayerType, IStrategy>();
public FiFaContext(Football ball)
{
Strategies.Add(PlayerType.Defender, new DefenderStrategy());
Strategies.Add(PlayerType.Forward, new ForwardStrategy());
Strategies.Add(PlayerType.GoalKeeper, new GoalkeeperStrategy());
}
}
/// <summary>
/// created enumerations to be used in dictionary instead of string
/// </summary>
public enum PlayerType
{
Defender,
Forward,
GoalKeeper
}
/// <summary>
/// the job of the defender is to defend its field
/// </summary>
public class DefenderStrategy : IStrategy
{
public void PlayingStrategyWith(Football ball)
{
Console.WriteLine("defend the ball");
}
}
/// <summary>
/// the job of a forward is to striker a goal
/// </summary>
public class ForwardStrategy : IStrategy
{
public void PlayingStrategyWith(Football ball)
{
Console.WriteLine("strike the ball");
}
}
/// <summary>
/// the job of the goal keeper is to prevent goals
/// </summary>
public class GoalkeeperStrategy : IStrategy
{
public void PlayingStrategyWith(Football ball)
{
Console.WriteLine("defend goals");
}
}
/// <summary>
/// a strategy defined for all the players in the team
/// </summary>
public interface IStrategy
{
void PlayingStrategyWith(Football ball);
}
/// <summary>
/// Just created a simple football class for the sake of example :)
/// </summary>
public class Football
{
public int Diameter { get; set; }
public void Bounces()
{
}
}
}
Sr. Azure Architect at Ennead Architects
8 年Non-static methods also helps when writing Unit test cases, you can mock them easily
Senior Software Engineer at Wolters Kluwer Tax & Accounting
8 年IMO the only downside with this approach is you have to change static methods to non-static(instance) in order to call them through the strategy interface.
PRINCE2 | Web | Mobile | Cloud | Automation
8 年maybe because it's on mobile. thanks for pointing it out man
Senior Software Engineer at Wolters Kluwer Tax & Accounting
8 年Why is the code not visible?