Strategy is a plan to achieve some goal. Let's see what Strategy design pattern says :
Strategy is a Behavioral type of design pattern.
Behavioral Design Pattern
It's about object communication, their responsibilities and how they communicate with each other.
The strategy pattern is a group of similar algorithms to be defined. The algorithm to be used for a particular requirement may then be called at run-time.
I will try to explain this pattern through an example,
Here we have an Employee class which has 3 properties: Name, Address and EmployeeDepartment . We want to get the bonus of employee and the calculation is done based on the department the Employee belongs to. In real time there will be some complex logic to calculate the bonus, for example purposes I am just returning some values.
We have a class EmployeeBonusCalculatorService which has a Method Calculate bonus. Calculate Bonus takes the Employee object as parameter and based on Employee type(switch case), it calls the respective Bonus calculation methods.
- public class Address {
- public string ContactName {
- get;
- set;
- }
- public string AddressLine1 {
- get;
- set;
- }
- public string AddressLine2 {
- get;
- set;
- }
- public string AddressLine3 {
- get;
- set;
- }
- public string City {
- get;
- set;
- }
- public string State {
- get;
- set;
- }
- public string Country {
- get;
- set;
- }
- public string PostalCode {
- get;
- set;
- }
- }
- public enum EmployeeDepartment {
- Sales,
- IT,
- Finance
- }
- public class Employee {
- public string Name {
- get;
- set;
- }
- public Address Address {
- get;
- set;
- }
- public EmployeeDepartment EmployeeDepartment {
- get;
- set;
- }
- }
- public class EmployeeBonusCalculatorService {
- public int CalculateBonus(Employee employee) {
- switch (employee.EmployeeDepartment) {
- case EmployeeDepartment.Finance:
- return CalculateBonusForFinance(employee);
- case EmployeeDepartment.IT:
- return CalculateBonusForIT(employee);
- case EmployeeDepartment.Sales:
- return CalculateBonusForSales(employee);
- default:
- throw new Exception("Unknown Error");
- }
- }
- private int CalculateBonusForSales(Employee employee) {
- return 300;
- }
- private int CalculateBonusForIT(Employee employee) {
- return 500;
- }
- private int CalculateBonusForFinance(Employee employee) {
- return 400;
- }
- }
Run the console application with
- class Program {
- static void Main(string[] args) {
- EmployeeBonusCalculatorService _service = new StrategyPattern.EmployeeBonusCalculatorService();
- int bonus = _service.CalculateBonus(new StrategyPattern.Employee {
- Name = "Max",
- Address = new Address {
- ContactName = "Marry",
- AddressLine1 = "302 Nagrajan Building",
- AddressLine2 = "Kadugudi",
- AddressLine3 = "Near Devi Temple",
- City = "Bangalore",
- State = "Karnataka",
- PostalCode = "560076",
- Country = "India"
- },
- EmployeeDepartment = EmployeeDepartment.Finance
- });
- Console.WriteLine(bonus);
- }
- }
Output would be : 400
Run the program with different EmployeeBBrect response.
Did you find any problem in the above code ?
Actually, this code will always give correct response but this code has a major design flaw.
Let's assume one more department is added, to accommodate new department what will we have to do ?
We'll have to modify our class EmployeeBonusCalculatorService and add 1 more switch case along with respective BonusCalculation Method which is breaking an Open/Closed Principle of SOLID principle which states that Entities should be open for extension but closed for modification. Also EmployeeBonusCalculatorService accomodating the logic of different Employee Departments which is breaking Single Responsibility Principle. Another principle that is breaking with the above design is "Change is one class is causing change in another class" If you remove or add any department type you need to come back to your service class and change the code accordingly. If you need to change one part of your system because of a change in another part of the sytem, it means system is tightly coupled.
Solution
Create separate Strategy class for each Department Type and each strategy should implement a common interface IDepartmentStrategy.
- public interface IDepartmentStrategy {
- int CalculateBonus(Employee emp);
- }
I have modified Employee class a bit and removed property EmployeeDepartment from it, may or may not be present (depends on domain experts, I have just removed as after design change it won't be required anymore)



Join the conversation! Your thoughts help the community grow.