Register | Login 
View Article  

Current Articles | Categories | Search | Syndication

Implementing the Strategy Pattern in .Net

By John Spano on Tuesday, February 21, 2006 :: 955 Views :: 2 Comments :: :: Design Patterns

Level: Intermediate + to Object Oriented Programming; Beginner + with .Net and C#
 
 
            Frequently with applications many of the operations they perform are dynamic depending on several factors.  Think about a common scenario, sales tax.  Tax amounts are based off the place where you live.  There are many different tax rates in each country.  A good method of implementing dynamic patterns like taxes is needed.  The strategy pattern covers this gap for us.
 
            The strategy pattern is very useful when a dynamic formula or data is needed.  In our situation it will allow us to swap out different tax objects when needed.  The pattern lets a class take on many different behaviors depending on the context in which it is used.
 
            The strategy patterns starts with an interface that defines the methods that each different behavior defines.  Our tax interface is simple, only one method that returns the (full amount of the price) * (the tax amount.).
 
[code]
using System;
 
namespace StrategyPattern
{
            public interface ITaxStrategy
            {
                        double CalculateTax(double amount);
            }
}
[/code]
 
This interface will be implemented in all of our tax strategy classes to give them a common base.
 
            Two simple classes are then created for calculating taxes for the USA and the UK.  Both tax rates are made up, 5% for the USA and 7% for the UK.
 
[code]
using System;
 
namespace StrategyPattern
{
            public class USATax : ITaxStrategy
            {
                        public USATax()
                        {
                        }
 
                        public double CalculateTax(double amount)
                        {
                                    return amount * 1.05;
                        }
            }
}
[/code]
 
[code]
using System;
 
namespace StrategyPattern
{
            public class UKTax : ITaxStrategy
            {
                        public UKTax()
                        {
                        }
 
                        public double CalculateTax(double amount)
                        {
                                    return amount * 1.07;
                        }
            }
}
[/code]
 
            To demonstrate the use of the two classes, we will create a simple inventory item class that represents an item in our stores inventory.  The class will just hold the price of the item.
 
[code]
using System;
 
namespace StrategyPattern
{
            public class InventoryItem
            {
                        private ITaxStrategy _ItemTax;
                        private double _ItemAmount;
 
                        public InventoryItem()
                        {
                        }
 
                        public void SetTax(ITaxStrategy tax)
                        {
                                    _ItemTax = tax;
                        }
 
                        public double ItemAmount
                        {
                                    get{return _ItemAmount;}
                                    set{_ItemAmount = value;}
                        }
                        public double ItemWithTax
                        {
                                    get{return _ItemTax.CalculateTax(_ItemAmount);}
                        }
            }
}
[/code]
 
            Now lets examine the code that makes the class use the strategy pattern.  A private variable names _ItemTax is declared as type ITaxStrategy.  This is our internal representation of which strategy we want the class to use.  The SetTax method allows us to set whichever strategy object we need to the inventory item.  The property ItemWithTax returns the item’s amount with the tax added into it by calling the CalculateTax method on our strategy object.
 
            To see the classes in motion this code can be used.
 
[code]
InventoryItem itm;
itm = new InventoryItem();
itm.ItemAmmount = (double)10;
 
USATax usaTax;
usaTax = new USATax();
 
UKTax ukTax;
ukTax = new UKTax();
 
itm.SetTax(usaTax);                           
 
MessageBox.Show(itm.ItemWithTax.ToString());
 
itm.SetTax(ukTax);                            
 
MessageBox.Show(itm.ItemWithTax.ToString());
[/code]
 
            The first thing we do is create an object of the InventoryItem class.  We then create a US tax object and a UK tax object.  After setting the tax object to our inventory class, the message boxes show the result.  You will get 10.5 for the first tax and 10.7 for the second showing the different strategies in action.
 
            While this is just a demonstration, in a real world application the tax objects would be created dynamically based on a registry key, configuration file, or based on the findings of a reflection call.  One technique I have used is to use reflection to query the install directory for a class that implements the ITaxStrategy interface.  When the product is installed, the user chooses what region they are in and the correct dll with the tax class is installed.  Reflection can then find this class and create an instance of it on the fly to pass to the inventory class.

Previous Page | Next Page

COMMENTS

this may not be entirely related to the point of your article, which was to explain and provide an example of the Strategy design pattern. However, for my own learning sake, I wanted to ask about your listing of a program that uses the Inventory item class and then uses the SetTax method to set the tax object to use. Is this preferable over letting the InventoryItem class set its internal Tax object itself (upon instantiation for instance) instead of the user of the class having to set it and requiring it to have to know more than perhaps it should?

Thanks! Great article!
-Chad Bryant

posted @ Saturday, March 11, 2006 4:34 PM by Anonymous User


Hi Chad. It would probably be ok to default the tax to some internal default based off the system your writing. If it's internal maybe default it to the current state's tax that the system is running in and then the upper level code can change it when needed. If your writing a framework for other people to use, you might not want to do this as you don't want to assume you know what they want. They might not do any tax as most internet stores don't.

posted @ Sunday, March 12, 2006 6:09 PM by John Spano


Click here to post a comment

Copyright (c) 2008 GSP Developers
Walling Info Systems | Terms Of Use | Privacy Statement