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.

Advertisements

Encapsulation of Change

storyThe change of the requirement is an enemy we must fight against when we develop the software project. Sometimes, the change of the requirement is endless, so we have to delay our project. Of course, our customers have not been patient with our delay. They would rather believe the difficulty we meet because of the change of requirement is the foxy excuse. The change is like a sword of Damocles over our head. As brooks said, there is no silver bullet in the process of software engineering. It is same that we can’t find the “silver bullet” to solve the problem of change. It’s a mission impossible. But don’t scare of it, we must face its difficulty actively. So Kent Beck, the leader of XP (Extreme Programming), announced that we must embrace the change. He provided the solution to solve it from the angle of Software Engineering Methodology. And now, this article will address issue how to solve the change in the process of developing the software project from the angle of Software Design Methodology. That is “Encapsulation of Change”.

Design Patterns is the best interpretation of “Encapsulation of Change”. No matter we use the Creational Pattern, Structural Pattern, or Behavioral Pattern, our objective is finding the change in Software, then encapsulating the change with abstraction and polymorphism. So, at the beginning of design, we not only implement the User Case, but also mark the existed change. Encapsulation of change means to discover the change or find the change. It is very important.

The objective of Creational Pattern is to encapsulate the change when creating an object. For example, it builds the specific abstract factory class when we use Factory Method Pattern or Abstract Factory Pattern. So this factory class encapsulates the creational change in the future. Bridge Pattern encapsulates the change when creating the object inside the product, so that we can replace it with the new object to meet the change of requirement.

As far as Structural Pattern, it focuses on the composite style between the object. When we change the structure of object, in fact the dependency between the objects would be changed. Of course if you want to use the Structural Pattern, you will use not only encapsulation, but also inheritance and aggregation. For example, Decorate Pattern describes the dependency between the decorator and the decorated object. The decorator is the abstract class so we can handle the change of the structure of the object. Similarly, Builder Pattern encapsulates the dependency of an implementation of the object. Composite Pattern encapsulates the recursive relationship between the objects.

Behavioral Pattern mainly focuses on the behavior of the object. It abstracts the behavior of the object into the specific abstract class or interface, so that it becomes more extensible, because the behavior is the most unstable part in the architecture. For instance, Strategy Pattern abstracts the strategy or algorithm into a sole class or interface in order to encapsulate the strategy. Command Pattern encapsulates the request. State Pattern encapsulates the state. Visitor Pattern encapsulates the style of visiting. Iterator Pattern encapsulates the algorithm of iteration.
By using the Design Patterns and encapsulating the change, it ensures the extensible of the architecture. Maybe we can’t sweep the nightmare which was brought by the change, however, if we can foresee some changes at the beginning of the design, it will avoid the trouble caused by the change in the future. So we can say Design Patterns should be a nice spear to fight against the change, although we can’t find out the “Silver Bullet”.