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

Design is an island

islandRecently, Kent Beck wrote a post which raise an opinion about software disign. It’s a nice metaphore for disign. That is: design is an island.

Kent wrote: Designing, then, is like walking an island. As long as you don’t get your feet wet, your design is okay. It means that we should try to design enough to meet the current set of requirement, otherwise you might fall into the water.

The “water line” is always changed because the tides always change the sea level. It means the change of requirement. That is inevitable. So we must beware not to let your feet wet. Kent said:”Design that are acceptable at other time of the year break down in the 10% of the year when you do 50% of your business.” So you should keep your design fresh. It’s the feature of the excellent architecture.

“Climbing higher on irland requires effort, just as improving designs require effort.” That’s right. You should spend your money and time to improve your disign.

Kent recoginzed the distributed application such as SOA and REST as the archipelago. It’s interesting. The analogy is perfect. It’s the extension of metaphore of island.

Kent alos raise his opinions, for example earthquake and island sank. More details visit the kent beck’s blog here. Enjoy it!

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”.

Scalability Principles

One of the most important aspects which should be considered about during you design the architecture of system is scalability. In the future, the requirement will be changed, the system will overload, the amount of user will be increased. If you don’t consider about the scalability of software system, you system is becoming rubbish.

Several days ago, InfoQ posted the useful article wrote by Simon, it was Scalability Principles. This article presented some principles and guidelines for building scalable software systems.

To build scalable software systems, you should try your best to decrease processing time. Thus the system can handle more user requests in the same amount of time. The article gave some strategies to achieve this goal.
* Collocation: reduce any overheads associated with fetching data required for a piece of work, by collocating the data and the code.
* Caching: if the data and the code can’t be collocated, cache the data to reduce the overhead of fetching it over and over again.
* Pooling: reduce the overhead associated with using expensive resources by pooling them.
* Parallelization: decrease the time taken to complete a unit of work by decomposing the problem and parallelizing the individual steps.
* Partitioning: concentrate related processing as close together as possible, by partitioning the code and collocating related partitions.
* Remoting: reduce the amount of time spent accessing remote services by, for example, making the interfaces more coarse-grained. Please consider the first law of distributed computing – don’t distribute your objects.

Scalability is inherently about concurrency. As Martin Fowler said in Patterns of Enterprise Application Architecture, concurrency is one of the most tricky aspects of software development. Whenever you have multiple processes or threads manipulating the same data, you run into concurrency problems. To handle the concurrency issue is very difficult, you have to consider many aspects, e.g. lock, resource contention, deadlock, concurrent transaction, etc. This article presented some simple principles that can help when building scalable systems.
* If you do need to hold locks (e.g. local objects, database objects, etc), try to hold them for as little time as possible.
* Try to minimize contention of shared resources and try to take any contention off of the critical processing path (e.g. by scheduling work asynchronously).
* Any design for concurrency needs to be done up-front, so that it’s well understood which resources can be shared safely and where potential scalability bottleneck will be.

In order to build a successful software system, you need to know what your goals and what you’re aiming for. Your design must meet not only the functional requirements, but also non-functional ones. Non-functional requirements include performance, security, scalability, interoperability etc. Before you build the software system, you need to know related information about non-functional requirements as early as possible.

You must keep test continuously in order to satisfy the non-functional qualities of a system.

Probably the most important principle for building scalable system is that, if you need your system to exhibit this characteristic, you have to design it in up front. Even you fulfill RUP or Agile methodologies, it is necessary still. At least, you should outline the overall view of the system architecture.