Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C#

Design Patterns - nuff said !

Rate me:
Please Sign up or sign in to vote.
4.85/5 (18 votes)
2 Sep 2010CPOL16 min read 45.1K   633   74   13
Principles of Design Patterns to answer why they exist, who should actually use them and their learning roadmap for beginners (using C#)

Download CommandPattern_SourceCode.zip - 56.41 KB

Download CommandPattern_Executable.zip - 18.76 KB  

Introduction        

Hello readers. As we all know, enough said about Design Patterns till now, my intent while writing this article was clear from very start. This article is not going to add another set of ‘black & white’ few MBs of digital text in the huge pile of Design Patterns material already available on the Internet. By saying this, be positive while criticizing me :-)

I don’t at all mean here that the existing material on Design Pattern is not of any worth but rather I want to say opposite of it; that there is more than enough good quality material available on the Internet at present that can explain you easily and clearly that what are Design Patterns and how they can be used in our software project’s design.

The irony of the Design Pattern is that ‘Design Pattern are practically applicable and get praise’ only when they are applied on big enterprise application projects that are usually based on object oriented design but they are usually targeted by the beginners (junior developers) merely because they make good portion of any software developer interview for getting a new big salary job.

Here things fail.

Don’t use the concept in a way that violates its core principles else you will never get it, at least this is true for me:-)

Time to begin - Learning Design Patterns

Start learning design pattern when:  

  • When you are involved with big enterprise application project having hundreds of classes to manage. Though in particular Design Patterns are not dependent on size of the project, but you will praise Design Patterns only if the project size is big enough to get benefited by the design pattern. To give you hint, Enterprise application development are usually considered to be big projects.
  • When your design is an object oriented design. Design patterns are proven and tested solutions to recurring problems that saves times instead of putting efforts in creating new design afresh. Design patterns are not related specifically to object oriented design domain(area), but yes software design patterns proposed by GoF were principally to target software designs that are based on object oriented principles.
  • You want to meet the needs of current software development scenario. Current software development scenario needs software designs that must have two properties:
  • Highly loosely coupled design 
  • Software development team is always ready to welcome frequent changes from the customer even after implementation phase. E.g. Agile software development methodology.
1_SDLC.jpg

Above three points define the core principles of design pattern. If your motivation for learning Design Patterns matches its core principles go for it else in my view it is better we should utilize our time in solidifying our object oriented principles which is a prerequisite for learning design patterns.

As you are reading further, I hope your intents are clear and your design is in great need of one of the many design patterns available. Welcome to the interesting world of software design and design patterns !

Design patterns – our software celebrity 

Design patterns gained popularity in computer science after the book ‘Design Patterns: Elements of Reusable Object-Oriented Software’ was published in 1994 by the so-called "Gang of Four" (Gamma et al.) I’m giving below image of front cover, so that beginners are familiar with the GoF and their famous book which has created the tide of ‘Design Patterns’ everywhere! (where it is needed or not! ). 

Design_Pattern_Book_Cover.JPG

Principles behind categorization of software design pattern

Again I want to put emphasis on the ‘Intent/Motivation'. While learning design pattern, its motivation or the problem it is trying to solve is so much important that, from the very start itself; efforts are made by Design Pattern writers that reader is able to get the intent of the design pattern that he/she is reading before exploring the implementation of that pattern. If every design pattern intent is clear in your head, then only you are able to trace out pieces in your software design that needs some design pattern and what exact design pattern is applicable in that situation. If you are not able to identify the places in your design that could be benefited by the design pattern usages, then reading thousand pages book on design pattern is not of any worth in my view.


The first thing that GoF done towards making 'the Intent' of the design patterns clear is by doing high level categorization of design patterns:-

  • Creational Design Patterns: If answers to any of the following question is ‘Yes’ then your design need one of the Creational Design Pattern
  • Is my design is having object creation logic?
  • Is object creation logic is complex and needs to be simplified?
  • Is object creation logic is subject to frequent changes in future and hence need to decoupled from client logic?
  • Structural Design Patterns: We need one of the Structural Design Pattern when
  • We are in process of building new types (specifying new class definitions) or extending existing types (through inheritance or composition) and we want that our new types addition will not make our design complex to understand and it works with same client code thus promoting code re-use by the virtue of loosely coupled design
  • Our design is affected by problems like class explosion, machine resources limitations etc.
  • Behavioral Design Patterns: We need one of the Behavioral Design Pattern when
  • We need to simply object communication by virtue of loosely coupled design
  • Having division of responsibility in context of algorithms and at the same time we want our design to be scalable with respect to addition/modification of algorithms

List of Design Patterns – Just taste now do not gulp them

By virtue of variety of problems in software engineering, there are variety of Design Patterns in each category where each design pattern is solving a problem which is nothing but a variant of a specified category under which it is grouped.

Popular design pattern introduced by GoF are as follows:

Category: Creational design patterns

  • Abstract Factory - Creates an instance of several families of classes
  • Builder - Separates object construction from its representation
  • Factory Method - Creates an instance of several derived classes
  • Prototype - A fully initialized instance to be copied or cloned
  • Singleton - A class of which only a single instance can exist

Category: Structural design patterns 

  • Adapter - Match interfaces of different classes
  • Bridge - Separates an object’s interface from its implementation
  • Composite - A tree structure of simple and composite objects
  • Decorator - Add responsibilities to objects dynamically
  • Façade - A single class that represents an entire subsystem
  • Flyweight - A fine-grained instance used for efficient sharing
  • Proxy - An object representing another object

Category: Behavioral design patterns

  • Chain of responsibility - A way of passing a request between a chain of objects
  • Command - Encapsulate a command request as an object
  • Interpreter - A way to include language elements in a program
  • Iterator - Sequentially access the elements of a collection
  • Mediator - Defines simplified communication between classes
  • Memento - Capture and restore an object’s internal state
  • Observer - A way of notifying change to a number of classes
  • State - Alter an object’s behavior when its state changes
  • Strategy - Encapsulates an algorithm inside a class
  • Template method - Defer the exact steps of an algorithm to a subclass
  • Visitor - Defines a new operation to a class without change

Please do not ever try to cram the above list of design patterns (probably you tempted to do so for your next interview). Believe me, if you try to get design patterns in this way they will go more far from you and that you don't want. Just start practicing each pattern one by one thoroughly and you will automatically starts remembering name of the concerned pattern as you go on spending some good time with that pattern.

Design patterns learning road map

Design pattern is not only:

  • UML diagram - describing its structure
  • Implementation - structural or real world sample code

It is much more than that.

The road map to master design patterns

For each design pattern we should explore following points:-

  1. Design pattern name
  2. Intent – What all design problems it solves
  3. Motivation – Understanding the design problems solved by this design pattern to appreciate its intent
  4. Applicability – Known practical applications. These applications are many of the few to give you a head start to explore new software design areas where this pattern is applicable. It will come with practice and experience so beginners do not worry about this now.
  5. Structure / UML diagram
  6. Participants – Roles of each class in design pattern structure described in point 5.
  7. Collaborations – Object communication
  8. Consequences – What things we can do after using design pattern which are not possible without using it.
  9. Implementation and Implementation issue – How to map design into language specific working application 
  10. Sample code – The application code
  11. Known issues – pattern limitations and their solution if any. 
  12. Related patterns – Compound pattern. Matter of advance research for beginners. 

Points 1,2,3,4,5,6,9 and 10 are for beginners. Once you are through with these points, please expand your knowledge about the design pattern by covering remaining points.

Surely, my intent of writing this article was not to put a series tutorial on Design Pattern (though in future, if you like this article surely I will try to write such comprehensive stuff) covering A to Z, but still to give you taste of design pattern I would like to introduce you with one of the popular GoF design pattern from the behavioral category – The Command Design Pattern.

I will follow the same road map described above to explain command pattern.

Real taste of design pattern using Command Pattern 

Intent 

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

Making our intents clear in the beginning is a sign of good start

Till now we had said understanding 'Intent' of the design pattern we are learning is most important. So, I hope after reading the intent of command pattern given above we are clear enough with Intent part. After clearing the intent let's move to motivation.

Hey! wait. I know some of them are feeling shy in accepting that above defintion is partially clear. Its perfectly ok at the beginning stage. Be truthful. If you need some explanation that really matters to you, we will explore things in detail. But do not proceed until unless previous things are not clear.

What is a request?

A function call is called a request.

What does it mean by encapsulating a request?

Let’s understand this by taking an example. We have one class named 'Server' which contains some methods(behaviors / functions).
Do not confuse 'Server' class name with some big Client-Server application architecture. It is a simple class, named 'Server' because of its role giving some services through its method implementations.

'Server' class has four methods:New,Open,Save and Print.

C#
public class Server
{
	public void New() //Method 1
	{
		Console.WriteLine("Server.New(): New file created.");
	}

	public void Open() //Method 2
	{
		Console.WriteLine("Server.Open(): Existing file opened.");
	}

	public void Save() //Method 3
	{
		Console.WriteLine("Server.Save(): Current file saved.");
	}

	public void Print(string message) //Method 4
	{
		Console.WriteLine("Server.Print(): " + message);
	}
}
Server class services are used by Client class. Code for client class is given below.
C#
class Client
   {
       public void Do()
       {
           Server serverObj = new Server();
           serverObj.New(); //Want to create new file
           serverObj.Open(); //Want to open existing file
           serverObj.Save(); //Want to save current file
           serverObj.Print("Hi!"); //Want to print some message
       }
   }  
Each of following statement represents a single request. Request is also known with terms like method invocation or function call.
Single request is made up of four parts:
  1. Instance of target object        :    serverObj
  2. Name of the method               :    Print
  3. Method parameters                :    "Hi"
  4. Method invocation statement   :    serverObj.Print("Hi!");

Using command design pattern we encapsulate all information that make up a request. An instance of command object contains all four details described above that is needed to successfully execute the request it is encapsulating.

Once the request is materialized into an object we can do all operations that are not possible with request (request can only be executed) like we can pass , stage, share, load into table or queue or instrument a request object. Encapsulated request is called Command or more specifically ConcreteCommand in context of command pattern.

Understanding term 'parametrize clients with different requests'?

Let’s assume we have two requests (function calls). These requests are made by Client object (code given below). We see in the below code that requests are statically (compile-time) bounded to the client object. If we have to make new requests we have to re-compile the client code.

C#
//Client - Without using command pattern
class Client
{
	public void DoSomeWork()
	{
		Server serverObj = new Server();
		serverObj.Func1(); //Bound at compile time
	}  
}

If we can do run-time assignments of requests by setting requests as parameters to client object then same client code can execute different requests without re-compiling the client code. Using command pattern; command object encapsulated requests are assigned to client object as parameters. This is the meaning of 'parametrized clients with different request'. Request parametrized client code is given below.

C#
class Program
{
	static void Main(string[] args)
	{
		//Command type - 1 encapsulating request - 1
		Command command1 = new Command();
		//Command type - 2encapsulating request - 2
		Command command2 = new Command();
		//This Client object takes parameterized client requests
		Client clientObj = new Client();
		clientObj.Command = command1; //Given encapsulated resuest 1 to client as parameter
		clientObj.DoSomeWork();//clientObj will do work according to assigned request 1 
		clientObj.Command = command2; //Given encapsulated resuest 2 to client as parameter
		clientObj.DoSomeWork();//clientObj will do work according to assigned request 2 
		Console.ReadLine();
	}
}

//This client object takes requests as parameters
class Client
{
	private Command _command;

	public Command Command
	{
	  get { return _command; }
	  set { _command = value; }
	}

	public void DoSomeWork()
	{
		_command.Execute();
	}
}

What does it mean by queuing or logging a request?

Using command pattern we can encapsulate a request(method call) into an object. Once the request is materialized into an object, all operations applicable for an object liking storing in message queue or storing an object for logging purpose can be done for a request.

Logging request means logging command objects that internally encapsulate requests for instrumentation or monitoring purpose.

What does it mean by supporting undoable operations?

Using command pattern in which requests/operations are encapsulated inside a command object, “Undo” (i.e. reverting back last undoable action) functionality implementation can be easily done.

Motivation  

Main motivation behind command pattern is ‘Simplified loosely coupled communication between sender and receiver of the request by encapsulating the request into object’.

Case 1: Understanding what is a tightly coupled design  

To understand the benefits of loosely coupled design, we must understand first actually what is a tightly coupled design and its drawbacks.

Below code shows tightly coupled design. Slight changes in the server code (Server class) like name of the methods etc. will lead to changes in the client code. This design surely not able to handle frequent change requests from the customer. This design is going to collapse.  

C#
class Program
{
	static void Main(string[] args)
	{
		Client clientObj = new Client();
		clientObj.Do();
		Console.ReadLine();
	}
}

class Client
{
	public void Do()
	{
		Server serverObj = new Server();
		serverObj.New(); //Want to create new file
		serverObj.Open(); //Want to open existing file
		serverObj.Save(); //Want to save current file
		serverObj.Print("Hi!"); //Want to print some message
	}
}

public class Server
{
	public void New()
	{
		Console.WriteLine("Server.New(): New file created.");
	}

	public void Open()
	{
		Console.WriteLine("Server.Open(): Existing file opened.");
	}

	public void Save()
	{
		Console.WriteLine("Server.Save(): Current file saved.");
	}

	public void Print(string message)
	{
		Console.WriteLine("Server.Print(): " + message);
	}
} 

Case 2: Loosely coupled design using command design pattern 

As a solution to above problem, to make our design loosely coupled so that sender and reciever of the request are decoupled and there are minimum changes on client code or the server code, if any one have to change as per customer requirements, we are going to solve the above design problem using command design pattern.

Participants

The Command pattern has three main components: the Invoker, the Command, and the Receiver. Participants are the collection of those classes that make up a given design pattern.

The command: The command pattern is used to express a request, including the call to be made and all of its required parameters, in a command object. The command may then be executed immediately or held for later use. The command object does not contain the functionality that is to be executed, only the information required to perform an action(actual functionality is in receiver object).


The receiver: The functionality is contained within receiver objects. This removes the direct link between the command definitions and the functionality, promoting loose coupling (This is the primary intent of any design pattern).

The Invoker: Neither of these object types is responsible for determining the time of execution of the command. This is controlled using an invoker or command processor.

Structure - UML diagram of command pattern

Usual_UML_Diagram.JPG

Detailed UML diagram of command pattern

The intent of giving detailed UML diagram of command pattern is here is to clarify exactly what does CLIENT participant mean in the usual UML diagrams.
Collectively, classes that create commands, assign receivers to newly created commands, set commands as parameters to invoker class and finally those classes that call/initiate invoker class method execution are called CLIENT in usual command pattern UML diagram. Clearing these type of small details is very much necessary while mastering design pattern.

Case_2_Loosely_Coupled_Design.JPG

Implementation - Sample code for loosely coupled design using command pattern

In the given below code, same problem is solved that is discussed in Case 1, i.e. Client object need to take four services from the Server object (New,Open,Save and Print) but now design uses command pattern and is loosely coupled. The output of the program in case 1 and case 2 are same.

Step 1:Receiver - Creating receiver class also called target object. 

C#
//Server.cs
public class Server
{
    //New
    //Open
    //Print
    //Save
} 

This is same code as written for Server class in Case 1 above.

Step 2:Command base class - Create base class from which all command class will derive.  

This class is an abstract class in this case. It can be interface also as per requirement.

C#
//Command.cs
public abstract class Command
{
    public abstract void Execute();
} 

Step 3:Create ConcreteCommands - These are our command objects that are going to encapsulate one request each of the receive (Server class).

C#
//Command.cs
//Encapsulate Server.New() request
public class NewCommand : Command
{
    Server targetObj;
    public NewCommand(Server targetObjInstance)
    {
        targetObj = targetObjInstance;
    }

    public override void Execute()
    {
        targetObj.New();
    }
}

//Encapsulate Server.Open() request
public class OpenCommand : Command
{
    ...same as NewCommand 
}

//Encapsulate Server.Save() request
public class SaveCommand : Command
{
    ...same as NewCommand
}

//Encapsulate Server.Print(string message) request
public class PrintCommand : Command
{
    Server targetObj;
    public string Parameter {get; set;}
    public PrintCommand(Server targetObjInstance)
    {
        targetObj = targetObjInstance;
    }

    public override void Execute()
    {
        targetObj.Print(Parameter);
    }
}

Step 4:Create Invoker class - This is a class that is hooked with the commands and can execute commands. 

It is the responsibility of the client to assign commands to this class, which this class executes for its client immediately or some time later. In this sample depending upon role of this class we are referring this class with name 'CommandProcessor'.

C#
//CommandProcessor.cs
using System.Collections.Generic;
namespace Design_Pattern_Command2_1
{
    //Command hooked class - the invoker class
    class CommandProcessor
    {
        List<Command> allHookedCommandsList = new List<Command>();
        
        private Command newCmd;
        public Command NewCmd
        {
            get { return newCmd; }
            set 
            { 
                newCmd = value;
                if (newCmd != null)
                    allHookedCommandsList.Add(newCmd);
            }
        }

        private Command openCmd;
        public Command OpenCmd
        {
            ...
        }

        private Command saveCmd;
        public Command SaveCmd
        {
            ...
        }

        private Command printCmd;
        public Command PrintCmd
        {
            ...
        }       
        
        public void RunCommands()
        {
            foreach (Command hookedCommand in allHookedCommandsList)
                hookedCommand.Execute();
            allHookedCommandsList.Clear();            
        }
    }
} 

Step 5:Create CommandsFactory class - This class is optional and is not essentially needed to be part of a command design pattern.

But it is good practice to make client not depended on command object creation logic. So, a new pattern is used called 'Factory Pattern' which creates new instances of commands for the client, which client sets inside the invoker object to execute commands finally. 

C#
//CommandsFactory.cs
namespace Design_Pattern_Command2_1
{
    //Decouples client from creating concrete command instances.
    public class CommandsFactory
    {
        static Server targetObject;
        static NewCommand newCmd;
        static OpenCommand openCmd;
        static SaveCommand saveCmd;
        static PrintCommand printCmd;

        static CommandsFactory()
        {
            targetObject = new Server();
            newCmd = new NewCommand(targetObject);
            openCmd = new OpenCommand(targetObject);
            saveCmd = new SaveCommand(targetObject);
            printCmd = new PrintCommand(targetObject);
            printCmd.Parameter = "Hi";
        }
        public static Command GetCommand(string commandType)
        {
            switch (commandType.ToUpper())
            {
                case "NEW": return newCmd;
                case "OPEN": return openCmd;
                case "SAVE": return saveCmd;
                case "PRINT": return printCmd;
                default: return newCmd;
            }
        }
    }
}

Step6: Client classes - There are three client classes in our case. 

CommandsFactory - A client class that creates new instances of the command objects using receiver objects, that is needed while creating new commands.
Client - Creates invoker class/CommandProcessor class object. Also creates or takes newly created objects and sets as parameters to invoker object. Pass populated invoker object with commands to other client object, that actually wants services of command encapsulated requests.
ServiceTakingClient - Calls invoker object and actually this client takes services of the commands encapsulated requests.

C#
using System;

//Pushing only one time real commands into commandprocessor to let it service other ServiceTakingClient or self.
class Client
{
    static void Main(string[] args)
    {
        CommandProcessor cmdProcessor = new CommandProcessor();
        //CommandProcessor should not be aware about actual command instances. It should be assigned to by the Client
   
    cmdProcessor.NewCmd = CommandsFactory.GetCommand("NEW");//Using
CommandsFactory Client is indirectly creating command instances.
        cmdProcessor.OpenCmd = CommandsFactory.GetCommand("OPEN");
        cmdProcessor.SaveCmd = CommandsFactory.GetCommand("SAVE");
        cmdProcessor.PrintCmd = CommandsFactory.GetCommand("PRINT");
        ServiceTakingClient actualClientObj = new ServiceTakingClient(cmdProcessor);
        actualClientObj.Do();//
        Console.ReadLine();
    }
}
    
//Service taker. 
//Service taking client can be different from actual command creating clients 
//which also creates the instance of commandprocessor(invoker) object.
class ServiceTakingClient
{
    CommandProcessor cmdProcessor;
    public ServiceTakingClient(CommandProcessor cmdProcessor)
    {
        this.cmdProcessor = cmdProcessor;
    }

    public void Do()
    {
        cmdProcessor.RunCommands();
    }
} 

Command pattern is also applicable in solving following problems:-

  • Loosely coupled design for windows desktop application menu system.
  • Logging of requests executed by the application for monitoring purpose 
  • Implementing Undo functionality inside the application
  • Processing commands as message queue. (Implementation of command pattern in this situation is left for reader). 

For the purpose of getting familiar with command pattern implementation for various design needs, I have included source code and executable of all possible application of command pattern with this article. 

Summary  

In principle Design Patterns are great tools to create good software designs but their learning should be approached with right intent. To help reader get real motivation behind learning command pattern we have discussed in detail about application areas of design pattern with clear road map to approach design pattern learning. In later sections of the article we discussed command pattern to get feel of how patterns applied in real life situations.

In this article I had tried to make the study of Design Patterns more clear and focused for the beginners, still it is a big topic to explore and I appreciate suggestions from readers for betterment of this article.
Happy Coding :-)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
Working as Senior Developer in US based MNC. Interested in R&D, writing/reading techinical articles, sci-fi movies, playing synthesizer.

Comments and Discussions

 
GeneralMy vote of 5 Pin
faizelw7-Sep-10 0:15
faizelw7-Sep-10 0:15 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.