Strategy Design Pattern with C#

Strategy design pattern is a behavioral design pattern. It is a particular software design pattern where algorithms are selected at runtime.

According to the book of Design Pattern (Gang of Four) – “Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. “

The key phrases of definition are “Family of algorithms”, “encapsulate”, and “interchangeable”. Actually, Strategy Pattern encapsulates a collection of functions that do similar yet not identical jobs. Client is not bound to call fixed methods; rather it can change its strategy dynamically at run time. Client don’t call any methods directly by instantiating concrete classes. It sets its strategy via context class.

There are three main parts in strategy pattern:

  1. Strategy – An interface that defines how the algorithm will be called.
  2. Concrete Strategy – The implementation of the strategy.
  3. Context – It holds the concrete strategy.

StrategyPattern

Implementation:

Suppose you have two lists of items. Item here integer numbers. Now, if you want to search an item from either of the lists. You can use either one of the algorithms from Linear Search or Binary search. Since binary search algorithm cannot search data without sorted list, we take here a sorted list. Now the strategy of client to use which one – Binary search or linear search. Let’s implement the problem by strategy pattern using c#.

Step 1: Create an Interface for Strategy

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StrategyPattern
{
///
/// Strategy defines how algorithm will be called
///

public interface ISearchStrategy
{
int Search(int[] list, int item);
}
}

Step 2: Create concrete strategy (Linear Search)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StrategyPattern
{
///
/// Concrete strategy(Linear Search Algorithm)
///

public class LinearSearch : ISearchStrategy
{
#region ISearchStrategy Members

public int Search(int[] list, int item)
{
Console.WriteLine("Linear Search");
int position = 0;

for (int i = 0; i < list.Count(); i++)
{
if (list[i] == item)
{
position = i;
break;
}
}

return position;
}

#endregion
}
}

Step 3: Create concrete strategy (Binary Search)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StrategyPattern
{
///
/// Concrete strategy(Binary Search Algorithm)
///

public class BinarySearch : ISearchStrategy
{
#region ISearchStrategy Members

public int Search(int[] list, int item)
{
Console.WriteLine("Binary Search");

int beg = 0;
int end = list.Count() - 1;
int mid = (int)((beg + end)/2);
int position = 0;

while (beg <= end && list[mid] != item)
{
if(item < list[mid])
end = mid - 1;
else
beg = mid + 1;

mid = (int)((beg + end)/2);
}

if (list[mid] == item)
position = mid;
else
position = 0;

return position;
}

#endregion
}
}

Step 4: Create a context class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StrategyPattern
{
///
/// Concrete strategy(Linear Search Algorithm)
///

public class LinearSearch : ISearchStrategy
{
#region ISearchStrategy Members

public int Search(int[] list, int item)
{
Console.WriteLine("Linear Search");
int position = 0;

for (int i = 0; i < list.Count(); i++)
{
if (list[i] == item)
{
position = i;
break;
}
}

return position;
}

#endregion
}
}

Step 5: Client class to demonstrate strategy pattern

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace StrategyPattern
{
///
/// Client class
///

class Program
{
static void Main(string[] args)
{

int[] sortedList = { 1, 2, 3, 4, 5, 6, 7, 8 };

//Instance of context to follow different strategies
SearchList objSearchList = new SearchList();

objSearchList.SetSearchStrategy(new BinarySearch());
objSearchList.Search(sortedList, 4);

objSearchList.SetSearchStrategy(new LinearSearch());
objSearchList.Search(sortedList, 7);

Console.ReadLine();
}
}
}

Output:
output_strategyPattern

Abstract Factory Pattern with C#

Abstract factory pattern is a creational design pattern. Creational design pattern is deals with object creation mechanism. Object creation mechanism is changed on the basis of problem. Abstract factory pattern provides an interface to create families of related or dependent objects without specifying their concrete class. It is identified on the basis of problem complexity. It is encapsulated the process of instantiation of family of classes. Abstract factory pattern is widely used in framework and libraries to encapsulate the family of classes.

Elements of Abstract Factory Pattern:

  1. Abstract Factory – An Interface to create families of related or dependent item object.
  2. Concrete Factory – Implement the interface to create families of related item object.
  3. Abstract Item – An interface to create concrete item object.
  4. Concrete Item – Implement the interface to create concrete item object.
  5. Client – Uses Interface (abstract Item) provided by abstract factory and access concrete object by this interface.

Implementation:

Here I implemented abstract factory pattern in International Cricket Team by C#. The UML diagram is given below.

AFP-1

Step 1: Create interface for Item class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AFP
{
///
/// Interface for Item class
///

public interface ICricketer
{
string BattingStrength();
string BowlingStrength();
string AllroundingStrength();
string IconPlayer();
}
}

Step 2: Create Factory Interface

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AFP
{
///
/// A Factory interface
///

public interface ICricketerFactory
{
ICricketer GetCricketer(CricketerBase cricketerBase);
}
}

Step 3: Define the type of Base object

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AFP
{

///
/// Define the type of Base Object
///

public enum CricketerBase
{
AustralianCricketer,
BangladeshiCricketer,
EnglishCricketer,
IndianCricketer,
PakistaniCricketer
}

}

Step 4: Create Concrete factory class for Asian Cricketer

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AFP
{

///
/// Concrete factory class for Asian Cricketer
///

public class AsianCricketerFactory : ICricketerFactory
{

#region ICricketerFactory Members

public ICricketer GetCricketer(CricketerBase cricketerBase)
{
ICricketer objICricketer = null;

switch (cricketerBase)
{
case CricketerBase.BangladeshiCricketer:
objICricketer = new BangladeshiCricketer();
break;
case CricketerBase.IndianCricketer:
objICricketer = new IndianCricketer();
break;
default:
break;
}
return objICricketer;
}

#endregion
}
}

Step 5: Create Concrete factory class for European Cricketer

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AFP
{
///
/// Concrete factory class for European Cricketer
///

public class EuropeanCricketerFactory : ICricketerFactory
{

#region ICricketerFactory Members

public ICricketer GetCricketer(CricketerBase cricketerBase)
{
ICricketer objICricketer = null;

switch (cricketerBase)
{
case CricketerBase.EnglishCricketer:
objICricketer = new EnglishCricketer();
break;
default:
break;
}
return objICricketer;
}

#endregion
}
}

Step 6: Create Item class for Bangladeshi Cricketer

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AFP
{

///
/// Item class for Bangladeshi Cricketer
///

public class BangladeshiCricketer : ICricketer
{
#region ICricketer Members

public string BattingStrength()
{
return "60%";
}

public string BowlingStrength()
{
return "70%";
}

public string AllroundingStrength()
{
return "85%";
}

public string IconPlayer()
{
return "Shakib Al Hasan";
}

#endregion
}
}

Step 7: Create Item Class for Indian Cricketer

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AFP
{

///
/// Item class for Indian Cricketer
///

public class IndianCricketer : ICricketer
{

#region ICricketer Members

public string BattingStrength()
{
return "85%";
}

public string BowlingStrength()
{
return "60%";
}

public string AllroundingStrength()
{
return "70%";
}

public string IconPlayer()
{
return "Shachin Tendulkar.";
}

#endregion
}
}

Step 8: Create Item class for Pakistani Cricketer

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AFP
{

///
/// Item class for Pakistani Cricketer
///

public class PakistaniCricketer : ICricketer
{

#region ICricketer Members

public string BattingStrength()
{
return "75%";
}

public string BowlingStrength()
{
return "85%";
}

public string AllroundingStrength()
{
return "75%";
}

public string IconPlayer()
{
return "Shahid Afridi.";
}

#endregion
}
}

Step 9: Create Item class for English Cricketer

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AFP
{

///
/// Item class for English Cricketer
///

public class EnglishCricketer : ICricketer
{

#region ICricketer Members

public string BattingStrength()
{
return "75%";
}

public string BowlingStrength()
{
return "80%";
}

public string AllroundingStrength()
{
return "70%";
}

public string IconPlayer()
{
return "Kavin Pietersen";
}

#endregion
}
}

Step 10: Create a client class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AFP
{

///
/// Client Class
///

class Program
{
static void Main(string[] args)
{
AsianCricketerFactory objAsianFactory = new AsianCricketerFactory();
ICricketer objIAsianCricketer = objAsianFactory.GetCricketer(CricketerBase.BangladeshiCricketer);
Console.WriteLine("Bangladesh Cricket Team\nBatting Strength:" + objIAsianCricketer.BattingStrength());
Console.WriteLine("Bowling Strength:" + objIAsianCricketer.BowlingStrength());
Console.WriteLine("Allrounding Strength:" + objIAsianCricketer.AllroundingStrength());
Console.WriteLine("Icon Player:" + objIAsianCricketer.IconPlayer());

Console.WriteLine();

EuropeanCricketerFactory objEuropeanFactory = new EuropeanCricketerFactory();
ICricketer objIEuropeanCricketer = objEuropeanFactory.GetCricketer(CricketerBase.EnglishCricketer);
Console.WriteLine("England Cricket Team\nBatting Strength:" + objIEuropeanCricketer.BattingStrength());

Console.WriteLine("Bowling Strength:" + objIEuropeanCricketer.BowlingStrength());
Console.WriteLine("Allrounding Strength:" + objIEuropeanCricketer.AllroundingStrength());
Console.WriteLine("Icon Player:" + objIEuropeanCricketer.IconPlayer());

Console.ReadLine();

}
}
}

Output:
AFP-Output

Factory Design Pattern with C#

Factory design pattern implements the concept of real world factories. Factory pattern is a creational design pattern. It deals with creating object without specifying exact class. In general, actors of factory patterns are a client, a factory and a product. Client is an object that requires another object for some purposes. Rather than creating the product instance directly, the client delegates this responsibility to the factory. The factory then creates a new instance of the product, passing it back to the client. Figure shows the whole process.

FP-1

Application

For an example, a banking application works with accounts. In this application there are different types of account like saving account and checking account. All accounts are derived from an abstract account name IAccount. The IAccount defines the withdraw, deposit and interest rate which must be implemented by the concrete accounts (saving account, checking account). If clients want to know the interest rate of the Saving Account. It just invoke the factory to create an instance of Saving account.  Being invoked factory, it creates an instance of the saving account and then client just get the interest rate by invoking interest method. The client uses the object as casted to the abstract class without being aware of the concrete object type. Over all implementation of this scenario is given below.

The advantage is in here that new account can be added without changing a single line of code in the client code. Here an object is created without exposing instantiation logic to the client. The object generation is centralized here.

Benefits:

  • Factory Pattern is the mostly used pattern.
  •  Decoupled the classes i.e eliminates the need to bind application specific class
  • The code only deals with the Interface.
  •  Factory Pattern provides the way to create multiple instances of classes.
  •  This provides a hook so that we can derive a sub-class to create different controls to display the data.
  •   Factory method connects the class hierarchies with minimum coupling.
  •  Product implementation may change over time but client remains unchanged.

Implementation

Step 1: Create an Interface – IAccount

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FactoryPattern
{
public interface IAccount
{
string Withdraw(int amount);
string Deposit(int amount);

double InterestRate();
}
}

Step 2: Create concrete classes

Saving account

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FactoryPattern
{
///
/// Concrete class SavingsAccount
///

public class SavingsAccount : IAccount
{
#region IAccount Members

public string Withdraw(int amount)
{
throw new NotImplementedException();
}

public string Deposit(int amount)
{
throw new NotImplementedException();
}

public double InterestRate()
{
return 12.5;
}

#endregion
}
}

Checking Account

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FactoryPattern
{

///
/// Concrete class CheckingAccount
///

public class CheckingAccount : IAccount
{
#region IAccount Members

public string Withdraw(int amount)
{
throw new NotImplementedException();
}

public string Deposit(int amount)
{
throw new NotImplementedException();
}

public double InterestRate()
{
return 10.24;
}

#endregion
}
}

Step 3: Create a Factory Object Enum

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FactoryPattern
{
///
/// FactoryObject Enum to configure object
///

public enum FactoryObject
{
SavingAccount,
CheckingAccount
}
}

Step 4: Create a factory class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FactoryPattern
{
///
/// Factory class to create object
///

public static class Factory
{
public static IAccount CreateObject(FactoryObject factoryObject)
{
IAccount objIAccount = null;

switch (factoryObject)
{
case FactoryObject.SavingAccount:
objIAccount = new SavingsAccount();
break;

case FactoryObject.CheckingAccount:
objIAccount = new CheckingAccount();
break;

default:
break;
}

return objIAccount;
}
}
}


Step 5: Access from client

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FactoryPattern
{
public class Program
{
public static void Main(string[] args)
{
//Create object by factory pattern
IAccount objSavingAccount = Factory.CreateObject(FactoryObject.SavingAccount);
IAccount objCheckingAccount = Factory.CreateObject(FactoryObject.CheckingAccount);

//Access object
Console.WriteLine("Saving Account Interest Rate: " + objSavingAccount.InterestRate());
Console.WriteLine("Checking Account Interest Rate: " + objCheckingAccount.InterestRate());

Console.ReadLine();

}
}
}