Home > Development > Open Closed Principal – Factory and Strategy Pattern

Open Closed Principal – Factory and Strategy Pattern


I had a good post on the previous post regarding this and was ask how could we do this if we added a location to the worker to make sure we used the correct ITaxationCalculator. Well here is how to do it with both the Factory and Strategy Pattern.

Enjoy.

using System;

namespace StrategyAndFactoryPattern
{

    public class Worker
    {
        private readonly string name;
        private readonly string location;
        private readonly decimal wage;
        private ITaxationCalculator calculator;

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

            calculator = TaxationCalculatorFactory.GetCalculator(location);

        }

        public string Name
        {
            get { return name; }
        }

        public string Location
        {
            get { return location; }
        }

        public decimal Wage
        {
            get
            {
                return wage;
            }
        }

        public void ChangeCalculator(ITaxationCalculator newCalculator)
        {
            calculator = newCalculator; 
        }

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

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

    public static class TaxationCalculatorFactory
    {
        public static ITaxationCalculator GetCalculator(string location)
        {
            switch (location)
            {
                case "Australia":
                    return new AustralianTaxCalculator();
                case "British":
                    return new BritishTaxCalculator();
                default:
                    throw new ArgumentException("Invalid Location");
            }
        }
    }

    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", "Australia", 100000);
            Console.WriteLine(b.CalculatedTax());
            b.ChangeCalculator(new BritishTaxCalculator());
            Console.WriteLine(b.CalculatedTax());
            Console.WriteLine(b.CalculatedTax(x => x * new decimal(1.23)));
            Console.ReadKey();
        }
    }
}

Blair

Advertisements
  1. scottg
    February 26, 2010 at 6:18 pm

    Would it be better to inject available TaxCalculators into a dictionary? Then there would be no maintenance on the factory. It seems the Worker class is now dependent on the TaxCalculator Factory, so I like your idea of letting a domain service handle this concern. Thanks a lot for your posts and replies – I’ve recently had a ‘moment of clarity’ with IoC and other design patterns and am very eager to learn and apply them!

    • February 26, 2010 at 7:43 pm

      The general advise out there is to avoid dependency inject when it comes to business objects. You could do it but i feels ugly. It doesnt really matter in this case though from my point of view. You could always change the Factory with an initial method and assign a stub to it for mocking purpose. I’ll show you in my next post tomorrow. Roy Osherove has a great book the art of unit testing which also shows this. This is where i learnt that technique from πŸ™‚ Wait till tomorrow and i’ll show you some sample code πŸ™‚ Btw IoC’s rock. I like Windsor as I am use to it. Have a read on my blog and send me a query via a comment if you want some more examples. Id be happy to share.

      • scottg
        March 1, 2010 at 4:12 pm

        I thought the advice was to inject dependencies that the object cannot live without? I know this is sample code, but it seems the Worker class has 3 (or 4) dependencies – name, location, wage, (and calculator). A worker cannot exist without these, so they are injected via the constructor. Any other good resource recommendations? I am working with Windsor, as well πŸ™‚

  2. March 2, 2010 at 1:25 am

    Google Domain Services using Double Dispatch. This is what you really want to do πŸ™‚

  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: