Home > Development > Open Closed Principle And The Strategy Pattern

Open Closed Principle And The Strategy Pattern


One of the principals of SOLID by Robert Martin aka Uncle Bob is the Open Closed Principal. The princal states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”. Basically if we have to start opening up a class file and making changes for new conditions all the time we are violating this. Image you have a worker class that can calculate the tax based on the country of the worker. You don’t want a dirty switch statement that you have to modify every time you have a new country you want to calculate the tax for. The example below use a clean interface and separates the responsibility to new classes based on a generic class and the consumer can change the calculating as required. You could also do this with functional programming styles using a lambda / delegate as also shown. The head first book has a great comment in it “encapsulate what varies”. This is soooo true think we are encapsulating the algorithm of calculating tax making the algorithm really flexible and a maintenance dream.

using System;

namespace StrategyPattern
{

    public class Worker
    {
        private readonly string name;
        private readonly decimal wage;

        public Worker(string name, decimal wage)
        {
            this.name = name;
            this.wage = wage;
        }

        public decimal CalculatedTax(ITaxationCalculator calculator)
        {
            return calculator.CalculateTaxPayable(wage);
        }

        public decimal CalculatedTax(Func<decimal,decimal> calc)
        {
            return calc(wage);
        }
    }

    public interface ITaxationCalculator
    {
        decimal CalculateTaxPayable(decimal salary);
    }

    public class AustralianTaxCalculator : ITaxationCalculator
    {
        public decimal CalculateTaxPayable(decimal salary)
        {
            return salary * new decimal(1.1);
        }
    }

    public class BritishTaxCalculator : ITaxationCalculator
    {
        public decimal CalculateTaxPayable(decimal salary)
        {
            return salary * new decimal(1.15);
        }
    }

    public class Program
    {
        public static void Main()
        {

            Worker b = new Worker("Blair",100000);
            Console.WriteLine(b.CalculatedTax(new AustralianTaxCalculator()));
            Console.WriteLine(b.CalculatedTax(new BritishTaxCalculator()));
            Console.WriteLine(b.CalculatedTax(x => x * new decimal(1.23)));
            Console.ReadKey();
        }
    }
}

Hope you find use in your coding adventures.

Blair..

Advertisements
  1. scottg
    February 25, 2010 at 3:48 pm

    Great article! What are your thoughts on adding a field (country code) to the Worker class and injecting the appropriate concrete TaxCalculator based on that value?

    • February 26, 2010 at 1:48 am

      I probably would not use dependency injection for you entities. I would use a Domain Service for that.

      Blair

  2. February 26, 2010 at 1:52 am

    You could inject a factory class and pass the string in and return an ITaxCalculator that way which is also very nice

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: