Saturday, March 7, 2009

Strategy Pattern and Delegate

Strategy Pattern will encapsulate a family of algorithm and make them interchangeable. So we can define the unified interface for the algorithm. It represents the polymorphism of OOD. For instance, we will develop a tool to calculate the tax. Assumed that the tax is divided into the personal income tax and enterprise tax. We can apply the Strategy Pattern into it and abstract the calculation of tax into the interface ITaxStrategy:

public interface ITaxStrategy

{

    double Calculate(double income);

}

 

The concrete tax strategies will implement the ITaxStrategy interface:

public class PeronalTaxStrategy : ITaxStrategy

{

    public double Calculate(double income)

    {

        //Implementation

    }

}

public class EnterpriseTaxStrategy : ITaxStrategy

{

    public double Calculate(double income)

    {

        //Implementation

    }

}

 

At the same time, we will define the utility class to provide the clients with convenient.

public class TaxOp

{

    private ITaxStrategy strategy;

    public TaxOp(ITaxStrategy strategy)

    {

        this.strategy = strategy;

    }

    public double GetTax(double income)

    {

        return strategy.Calculate(income);

    }

}

Now, the clients can invoke the related operation of TaxOp class to get the tax according to concrete strategy object which is passed as parameter of constructor.

public class App

{

    public static void Main(string[] args)

    {

        TaxOp op = new TaxOp(new PersonalTaxStrategy());

        Console.WriteLine(“The Personal Tax is :{0}”, op.GetTax(1000));

    }

}

 

It follows the idea of OOD. However, we can make use of the delegate syntax in C# for some simple algorithms. It will simplify our implementation. Maybe it will violate the idea of OOD, but it provides the extensibility also.

 

For the same example given before, we can modify the interface to delagate type:

public delegate double CalculateTax(double income);

 

Of course, we should provide the different implemenation:

public class Tax

{

    public static double CalculatePersonalTax(double income)

    {

        //Implementation

    }

    public static double CalculateEnterpriseTax(double income)

    {

        //Implementation

    }

}

 

Accordingly, we must modify the TaxOp Class:

public class TaxOp

{

    private CalculateTax calDel;

    public TaxOp(Calculate calDel)

    {

        this.calDel = calDel;

    }

    public double GetTax(double income)

    {

        return calDel(income);

    }

}

 

And the implementation of Clients program:

public class App

{

    public static void Main(string[] args)

    {

        TaxOp op = new TaxOp(new CalculateTax(Tax.CalculatePersonalTax));

        Console.WriteLine(“The Personal Tax is :{0}”, op.GetTax(1000));

    }

}

 

Two solutions are more or less the same. The code snippet is also similar. But the idea based on the essence of design is different completely. It’s the difference between OO and OP. The former encapsulates the behavior in an object; the latter handles the method directly, and uses the delegate to provide the extensibility. In fact, the delegate represents the feature of Functional Programming nearly. It seams like a pointer to the function in C++. In other words, the delegate is another ways of abstraction. It is more flexible than interface type. After C# 2.0 introduced the anonymous method, and C# 3.0 introduced the Lambda expression, delegate becomes more and more useful and popular on C# programming. Before C# 2.0, I prefer to interface; now I prefer to delegate. Even we may use the delegate type to provide the brand new implementation of some design patterns such as Strategy Pattern, Command Pattern etc.

No comments: