Gang of Four (GOF) Design Patterns
 
Published: 05 Jun 2006
Unedited - Community Contributed
Abstract
In this article we will be taking a look at several Gang Of Four (GOF) design patterns with the help of code samples.
by John Spano
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 39639/ 36

Implementing the Singleton Design Pattern in .NET

Level:  Intermediate to Object Oriented Programming

Design Patterns are a very useful programming concept that is often forgotten about in the heat of a programming project.  Design Patterns are basically code design templates that have been perfected over the years by many different programmers and architects.  They represent repetitive design concepts that do not differ much.

One of the most famous design pattern books is called Design Patterns – Elements of Reusable Object Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides.  They are collectively known as the Gang of Four (GOF) and the book is commonly known as the GOF book.  I highly recommend this book as you learn object oriented programming.  It will start to make you think in patterns, which is essential to software.  Every application follows some similar concepts and patterns.

Many programming tasks are standard for each software project.  There are many times when you want a single instance of an object throughout the entire application.  Enter the Singleton design pattern.  This pattern limits an object to one instance in the entire application and returns that instance when called on.

Here is a simple working singleton class.

Listing 1

using System;
namespace Singleton
{
  public class Singleton
  {
    private static Singleton _instance = null;
 
    private Singleton(){}
 
    public static Singleton Instance()
    {
      if (_instance == null)
      {
        _instance = new Singleton();
      }
      return _instance;
    }
 
  }
}

Let us go over the code to see what happens.  First we create a class named Singleton.  It has a single member variable of type Singleton named _instance that is initialized to null.  This is the one instance of the class that all of our programs will use.  We make the constructor of the class private so that programs cannot create instances of the class directly.

The one function created for the class is named Instance and returns an object of type Singleton.  In the function we simply check to see if the internal variable is null, and if so create a new one.  This instance is then returned.

To verify our code the following can be run.

Listing 2

Singleton S1; 
Singleton S2; 

S1 = Singleton.Instance(); 
S2 = Singleton.Instance(); 
MessageBox.Show(S1.Equals(S2).ToString());

This will show true in the message.

The above code is fine for single threaded applications.  Now we will examine a thread safe version of the singleton.

Listing 3

using System;
using System.Threading;
 
namespace Singleton
{
  public class MultiSingleton
  {
    private static volatile MultiSingleton_instance = null;
 
    private MultiSingleton(){}
 
    public static MultiSingleton Instance()
    {
      if (_instance == null)
      {
        lock(typeof(MultiSingleton))
        {
          if (_instance == null)
          {
            _instance = new MultiSingleton();
          }
        }
 
      }
      return _instance;
    }
 
  }
}

This version of the singleton patterns is safe for multithreaded applications.  Let us examine the code to see what has changed.  There are only two significant changes: the definition of the instance variable and the lock work in the function.

The definition of the _instance variable has added the volatile keyword.  This is to ensure that the compiler does not do any memory optimizations on our variable by reordering our code in the function.  Without the volatile keyword the compiler might decide to remove the double check in the function.

The function can seem confusing at first, but makes sense after looking at it.  A double check is used to see if the instance variable is null.  We do this because no two threads would ever pass both conditions at the same time.  If the inner check was left out, two threads could run the null check at the same time.  Both would pass so both threads would then obtain the lock and create a new instance of the singleton.  The inner check prevents the second thread from creating the instance, since it would not be null after the first.  This brings up the point: Why not we just write it like the following then?

Listing 4

public static MultiSingleton Instance()
{
  lock(typeof(MultiSingleton))
  {
    if (_instance == null)
    {
      _instance = new MultiSingleton();
    }
  }
  return _instance;
}

This code would work fine and be perfectly thread-safe. We do not use the above because the lock is always entered.  This is not as fast as the previous double check code where the lock is avoided when the instance is not null.

The singleton is a very common design pattern.  I have kept the code shown as close as possible to the GOF book’s implementation of the pattern.  There are other ways to write a singleton in .NET, but the GOF implementation is one of the most common throughout other languages.  If you understand patterns and remember their names, it gives you the ability to converse with many other programmers on the same level.   If an architect calls for a singleton, that is what will be asked for.  The architect will not ask for a single instance of this class throughout the application.

Implementing the Factory Pattern in .NET

Level: Beginner + to Object Oriented Programming; Beginner + with .Net and C#

The factory design pattern is very simple.  Several other patterns build off of it though, so it is a common base pattern.  You use this pattern when one or more of the following are true.

A class cannot anticipate the class of the object it must create.

A class wants its subclasses to specify the objects it creates.

Classes delegate responsibility to one of several helper subclasses and you want to localize the knowledge of which helper subclass is the delegate (GOF).

The class is easy to implement and consists of an identifier, either named constants or an enum, and a switch statement.  For our example we will be creating dog objects.  As with any good OO design, we start with an interface for our related objects.

The IDog interface:

Listing 5

public interface IDog
{
void Bark();
void Scratch();
}

We just define a couple of simple methods for our dogs to do.

For the two actual concrete dog classes, we define a bulldog and poodle class:

Listing 6

public class CPoodle: IDog
{
  public CPoodle()
  {
    Console.WriteLine("CreatingPoodle");
  }
  public void Bark()
  {
    Console.WriteLine("Yip Yip");
  }
  public void Scratch()
  {
    Console.WriteLine("ScratchScratch");
  }
}
 
public class CBullDog: IDog
{
  public CBullDog()
  {
    Console.WriteLine("CreatingBulldog");
  }
  public void Bark()
  {
    Console.WriteLine("Wooof Wooof");
  }
  public void Scratch()
  {
    Console.WriteLine("Scratch SlobberScratch");
  }
}

Our factory class is static and contains one method to return the correct dog.

Listing 7

public class CDogFactory
{
  public enum DogType
  {
    Poodle, Bulldog
  } static CDogFactory(){}
  public static IDog CreateDog(DogTypeTypeOfDog)
  {
    switch (TypeOfDog)
    {
      case DogType.Bulldog:
        return new CBullDog();
      case DogType.Poodle:
        return new CPoodle();
      default:
        throw newArgumentException("Invalid Dog Type!");
    }
  }
}

We make the class static so we do not need an instance of the class.

To test the class, I have created a simple function.  Our test function returns the dogs and uses them.  In a more real world application, the type of dog would have been determined by the user or through program logic.

Listing 8

IDog dog1;
IDog dog2;
 
dog1 = CDogFactory.CreateDog(CDogFactory.DogType.Bulldog);
dog2 =CDogFactory.CreateDog(CDogFactory.DogType.Poodle);
 
dog1.Bark();
dog1.Scratch();
 
dog2.Bark();
dog2.Scratch();
Implementing the Visitor Design Pattern In .NET

Level: Intermediate to Object Oriented Programming; Beginner + with .NET and C#

The visitor design pattern is very useful in situations in which normal polymorphism will not work because we have fundamentally different objects, with different interfaces, that you want to work on your concrete main object.  The pattern is used to give us a way to do these different operations on the object.  According to the GOF book, you use the visitor pattern when:

1. An object structure contains many classes of objects with differing interfaces and you want to perform operations on these objects that depend on their concrete classes.
2. Many distinct and unrelated operations need to be performed on objects in an object structure and you want to avoid "polluting" their classes with these operations.  Visitor lets you keep related operations together by defining them in one class.  When the object structure is shared by many applications, use Visitor to put operations in just those applications that need them.
3. The classes defining the object structure rarely change, but you often want to define new operations over the structure.  Changing the object structure classes requires redefining the interface to all visitors, which is potentially costly.  If the object structure classes change often, then it is probably better to define the operations in those classes (GOF333).

We first start by defining a base class for our visitor object collection.  We will use our common Cbulldog object for our example.

Listing 9

public class BaseVisitor
{
  public BaseVisitor(){}
  virtual public void VisitBulldog(CBulldogdog){}
}

The code is pretty simple, having only a single method that takes an instance of the bulldog to work on.  We can then derive concrete instances of visitors from this base.  We will derive two for our example, one that changes our dog’s age and another that changes his bark.  First we will look at our Cbulldog class.  It has not changed much; there is only one new method.

Listing 10

public class CBulldog
{
  private int _Age;
  private string _BarkString;
  public CBulldog()
  {
    _Age = 0;
    _BarkString = "Woof";
  }
  public void TakeVisitor(BaseVisitor bv)
  {
    bv.VisitBulldog(this);
  }
  public void Bark()
  {
    Console.WriteLine(_BarkString);
  }
  public int MyAge
  {
    get
    {
      return _Age;
    }
    set
    {
      _Age = value;
    }
  }
  public string MyBark
  {
    get
    {
      return _BarkString;
    }
    set
    {
      _BarkString = value;
    }
  }
}

The TakeVisitor method allows our class to accept any visitor that is derived from BaseVisitor.  The method simply calls the VisitBulldog method and passes a pointer to the current class.

Now we look at our concrete derived visitor classes.  First, the class that will change the dog’s age:

Listing 11

public class AgeVisitor: BaseVisitor
{
  public AgeVisitor(): base(){}
  public override void VisitBulldog(CBulldogdog)
  {
    dog.MyAge = 5;
  }
 
}

 Listing 12 is the class that will change his bark.

Listing 12

public class BarkVisitor: BaseVisitor
{
  public BarkVisitor(): base(){}
  public override void VisitBulldog(CBulldogdog)
  {
    dog.MyBark = "Yip Yip";
  }
}

As you see, all that the methods do are to act upon the dog object passed to them.  You can make them as complex or simple as needed.

Our test code for the example:

Listing 13

CBulldog Mydog;
Mydog = new CBulldog();
 
Mydog.Bark();
Console.WriteLine(Mydog.MyAge.ToString());
 
AgeVisitor av;
av = new AgeVisitor();
Mydog.TakeVisitor(av);
Console.WriteLine(Mydog.MyAge.ToString());
 
BarkVisitor bv;
bv = new BarkVisitor();
Mydog.TakeVisitor(bv);
Mydog.Bark();

If you watch the output window, you will see that the calls to TakeVisitor change the dog’s information.

This pattern can help keep your objects cleaner when there are many different types of visitors you want to use.

Implementing the Strategy Pattern in .NET

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

Listing 14

using System;
namespace StrategyPattern
{
  public interface ITaxStrategy
  {
    double CalculateTax(double amount);
  }
}

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.

Listing 15

using System;
 
namespace StrategyPattern
{
  public class USATax: ITaxStrategy
  {
    public USATax(){}
 
    public double CalculateTax(double amount)
    {
      return amount * 1.05;
    }
  }
}
 
using System;
 
namespace StrategyPattern
{
  public class UKTax: ITaxStrategy
  {
    public UKTax(){}
 
    public double CalculateTax(double amount)
    {
      return amount * 1.07;
    }
  }
}

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 hold the price of the item.

Listing 16

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);
      }
    }
  }
}

Now let us examine the code that makes the class use the strategy pattern.  A private variable named _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 the following code can be used.

Listing 17

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());

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.

Implementing the Command Pattern in .NET

Level: Beginner + to Object Oriented Programming; Beginner + with .Net and C#

The command pattern is a very useful pattern when you want to give your users the ability to do certain things and undo them.  Typical examples are the undo and redo on many programs today.  This functionality is accomplished with the command pattern.  The GOF book says to use a command pattern when:

1. Parameterize objects by an action to perform
2. Specify, queue, and execute requests at different times
3. Support undo (GOF235)

The pattern encapsulates the commands of your application to self contained classes.   For our example, we will revisit the dog example I have used before and play God for a while.  Our operations will be to magically increase and decrease our bulldog's age.  Since we are almighty, we of course can change our minds and undo our meddling.

First we start with a very simple Bulldog class.

Listing 18

public class CBulldog
{
  private int _Age;
  private string _BarkString;
  public CBulldog()
  {
    _Age = 0;
    _BarkString = "Woof";
  }
  public void Bark()
  {
    Console.WriteLine(_BarkString);
  }
  public int MyAge
  {
    get
    {
      return _Age;
    }
    set
    {
      _Age = value;
    }
  }
  public string MyBark
  {
    get
    {
      return _BarkString;
    }
    set
    {
      _BarkString = value;
    }
  }
}

All the class does is to keep up with the dog’s age, provide a method to change it and allows for the dog to bark.  The bark method writes the dog's bark out to the console window.

For our command classes, we first define three interfaces then our main command classes.  The interfaces allow different kinds of commands to be acted upon as the same type of class.  For our example, we will use two different commands, one to change the dog’s age and another to change how he barks.

First we create our interfaces:

Listing 19

public interface IBaseCommand
{
  void Undo();
}
 
public interface IAgeCommand: IBaseCommand
{
  void AddAge(int age);
}
 
public interface IBarkCommand: IBaseCommand
{
  void ChangeBark(string Newbark);
}

We base the two main command interfaces of a generic one that allows for an undo.  This will allow us to iterate over all interfaces later and undo them as a group.  We can cast any IAgeCommand or IBarkCommand down to an IBaseCommand.

Now for our two classes that encapsulate the commands.  They are pretty straight forward.  Each takes a parameter of the dog to operate on in the constructor and saves off any relevant information like the last age, etc.

Listing 20

public class AgeCommand: IAgeCommand
{
  private CBulldog _OurDog;
  private int _OldAge;
  public AgeCommand(CBulldog o)
  {
    _OurDog = o; //dog to work on
  }
  public void AddAge(int age)
  {
    _OldAge = _OurDog.MyAge;
    _OurDog.MyAge = age;
  }
  public void Undo()
  {
    _OurDog.MyAge = _OldAge;
  }
}
 
public class BarkCommand: IBarkCommand
{
  private CBulldog _OurDog;
  private string _OldBark;
  public BarkCommand(CBulldog o)
  {
    _OurDog = o; //dog to work on
  }
  public void ChangeBark(string Newbark)
  {
    _OldBark = _OurDog.MyBark;
    _OurDog.MyBark = Newbark;
  }
  public void Undo()
  {
    _OurDog.MyBark = _OldBark;
  }
}

Our test of the code will be to create a dog, show its initial settings, change them, show the new settings and then revert back to the original.  For simplicity, we store the list of used commands in an ArrayList object.

Listing 21

CBulldog oDog;
ArrayList cmd = new ArrayList();
 
oDog = new CBulldog();
 
AgeCommand a1 = new AgeCommand(oDog);
Console.WriteLine(oDog.MyAge.ToString());
a1.AddAge(4);
cmd.Add(a1);
Console.WriteLine(oDog.MyAge.ToString());
 
BarkCommand b1 = new BarkCommand(oDog);
oDog.Bark();
b1.ChangeBark("Yip Yip");
cmd.Add(b1);
oDog.Bark();
 
//at this point we have a dog that as beenchanged
//we also have an array that has the command
//objects that were used for the change.
//To undo, just loop through the arraylistbackwards
cmd.Reverse();
foreach (IBaseCommand bse in cmd)
{
  bse.Undo();
}
 
oDog.Bark();
Console.WriteLine(oDog.MyAge.ToString());
Implementing the Proxy Design Pattern In .NET

Level: Beginner + to Object Oriented Programming; Beginner + with .NET and C#

The Proxy design pattern shows a way to do just-in-time loading of objects that would consume too much memory to keep around or take too much time to load.  This can be a very useful pattern for many applications.  A good example of this pattern is in Microsoft Office.  When you open a large Word document that has many embedded pictures, Office does not load them all at the time you open the document.  As you scroll down, Office will pull the pictures from the disk file and insert them into the document.  You can see this by scrolling very fast down the document.  It takes a second or so for the document to “catch up” to you and show the visible images.

For our example, we will have a part object that represents a manufacturer's part in a database.  It has a FullDescription property that could be many pages of text.  We do not want to load this text unless the user really wants to see it.

We first start by creating a wrapper for the description.  It is a very simple object that just exposes the text we want to return.  In a real world application the text would come from a database or something similar.

Listing 22

using System;
 
namespace ProxyDesignPattern
{
  public class PartDescription
  {
    private string _PartNumber;
    private string _PartText;
    public PartDescription(string PartNumber)
    {
      _PartNumber = PartNumber;
//load text now  For the demo, we just make sometext up.
      if (_PartNumber == "1")
      {
        _PartText = "Pages of text for part1";
      }
      else if (_PartNumber == "2")
      {
        _PartText = "Pages of text for part2";
      }
      else
      {
        _PartText = "Part Not Found";
      }
    }
    public string ReturnText
    {
      get
      {
        return _PartText;
      }
    }
  }
}

The Part class is also simple.  It just allows entry of the part number and then has a method to return the part text.

Listing 23

using System;
namespace ProxyDesignPattern
{
  public class Part
  {
    private string _PartNumber;
    private PartDescription _PartDescription;
    public Part()
    {
      _PartDescription = null;
    }
 
    public string PartNumber
    {
      get
      {
        return _PartNumber;
      }
      set
      {
        _PartNumber = value;
      }
    }
    public string FullDescription
    {
      get
      {
        if (_PartDescription == null)
        {
          _PartDescription = newPartDescription(_PartNumber);
        }
        return _PartDescription.ReturnText;
      }
    }
  }
}

The interesting method is FullDescription.  You will see that the get method first checks to see if the _PartDescription object is null or not.  If not, then we do not need to create the object as it has already been done before.  If we do not need the text after the call, we can set the object to null after returning the text.  This would be useful if we did not want to keep the overhead of the part text around.  After passing the text to some other program, we can clear it in our object.  Here is the rewrite of the function.

Listing 24

public string FullDescription
{
  get
  {
    try
    {
      if (_PartDescription == null)
      {
        _PartDescription = newPartDescription(_PartNumber);
      }
      return _PartDescription.ReturnText;
    }
    catch
    {
      return "Error";
    }
    finally
    {
      _PartDescription = null;
    }
  }
}

We have added error handling in this function to allow for a finally block to null the object.

References

Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides. ISBN: 0201633612.
View On Amazon.com

Summary

In this article you have learned how to deal with design patterns using .NET with the help of code samples.



User Comments

No comments posted yet.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-18 4:38:18 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search