Design Patterns Tutorial in C#

.NET programming topics
Post Reply
User avatar
Saman
Lieutenant Colonel
Lieutenant Colonel
Posts: 828
Joined: Fri Jul 31, 2009 10:32 pm
Location: Mount Lavinia

Design Patterns Tutorial in C#

Post by Saman » Fri Feb 05, 2010 4:39 am

This brief tutorial is about design patterns. We’ll look at some of the most commonly used patterns and how they look in C#. We will be discussing following patterns.
  • The Decorator Pattern
  • The Abstract Factory Pattern
  • The Observer Pattern
  • The Facade Pattern
  • The Visitor Pattern
What Is A Design Pattern?
A design pattern is, simply, a solution to a recurring problem in software development. Design patterns outline communication and interaction between objects in common programming situations.

When talking about design patterns the book “Design Patterns: Elements of Reusable Object-Oriented Software“, by the Gang Of Four, is considered the authority on the subject. Their patterns are considered the foundation of all other patterns that have emerged. They divide patterns into three categories: Creational, Structural, and Behavioral.

What Will This Tutorial Cover?
In this tutorial we will look at the some common patterns we see in real-world programming situations. We will discuss each pattern and look at real-world C# code that implements the pattern.

The Decorator Pattern
Design patterns are something that interests me and I don’t seem to get bored reading or talking about them. I am not sure why that is, my wife can barely endure 5 sentences about the subject, she’s one of those creative types that don’t understand all the fuss about logic and math. Perhaps my interest stems from the fact that I, and many programmers, use design patterns everyday, lots of times not even knowing that it is a design pattern.

Looking back I realize that I used a number of patterns not knowing that they were some documented standard for approaching a situation. Probably the most common of these patterns that I used was the Decorator Pattern. I find that I use this pattern frequently when reworking older code that I have written when I want to guarantee that my new code won’t break any existing functionality. I also use this pattern extensively when I am given charge of someone else’s code for whatever reason.

Sometimes the existing code must be maintained or is very fragile, the Decorator Pattern is great for this type of situation.

Definition
The definition of the Decorator Pattern, according to Wikipedia, is:
The decorator pattern can be used to make it possible to extend (decorate) the functionality of a class at runtime. This works by adding a new decorator class that wraps the original class. This wrapping is typically achieved by passing the original object as a parameter to the constructor of the decorator when it is created. The decorator implements the new functionality, but for functionality that is not new, the original (wrapped) class is used. The decorating class must have the same interface as the original class.
The Situation
Lets say you are assigned a project that a colleague was working on. Maybe this co-worker has fallen ill or has decided to leave the company, for whatever reason, this is now your responsibility. Your manager hands the project off to you and explains the details of the project and the new features that are required.

The application is a dog registration program that your city is currently using to manage all annual dog registrations. The program has been deployed for nearly a year and now the city has decided that they would like to track when a dog gets picked up by the dog catcher. Based on this history, dogs that regularly get into trouble will cost more to register to offset the cost of employing the dog catcher.

Once you take a look at the code you discover that your coworker did not write any unit tests for this application. How will you know if your changes are going to introduce bugs into the existing features? Simple, you don’t. Without unit tests, the only way to determine if something gets broken is to manually fire up the UI and test each feature and all the possible combinations that feature may entail. Not something we want to do. That’s when the Decorator Pattern comes into play. It will allow us to wrap the new functionality around existing objects so that we do not disrupt the other code using the existing objects.

The Existing Code
The existing model looks like this.

Code: Select all

internal interface IDog {
    int Id { get; set; }
    string Name { get; set; }
    string Breed { get; set; }
    string Address { get; set; }
    DateTime RegisterDate { get; set; }
    int RegistrationCost { get; }
}

public class Dog : IDog {
    public Dog() : this(new DogRepository()) { }


    public Dog(IRepository repository) {
        _repository = repository;
    }

    private IRepository _repository;

    private int id;
    public int Id {
        get { return id; }
        set { id = value; }
    }

    private string name;
    public string Name {
        get { return name; }
        set { name = value; }
    }

    private string breed;
    public string Breed {
        get { return breed; }
        set { breed = value; }
    }

    private string address;
    public string Address {
        get { return address; }
        set { address = value; }
    }

    private DateTime registerDate;
    public DateTime RegisterDate {
        get { return registerDate; }
        set { registerDate = value; }
    }

    public int RegistrationCost {
        get { return 25; }
    }
}
This may not be the prettiest code but it is what it is. You can chalk that up to your coworker not being as good of a programmer as you or me just being lazy with the example code.

The New Requirements
So as mentioned above, the city now wants to track how often a dog is picked up by the dog catcher to determine if the registration cost for that dog should be higher. These details will be stored in a new database table called Infractions. The corresponding model class will look like this.

Code: Select all

public class Infraction {
    public Infraction() { }


    private int id;
    public int Id {
        get { return id; }
        set { id = value; }
    }

    private int dogId;
    public int DogId {
        get { return dogId; }
        set { dogId = value; }
    }

    private string reason;
    public string Reason {
        get { return reason; }
        set { reason = value; }
    }

    private DateTime infractionDate;
    public DateTime InfractionDate {
        get { return infractionDate; }
        set { infractionDate = value; }
    }
}
The Decorator Code
Now that we know our new requirements and have defined the structure of the new information we can get to work building our decorator. We’ll create an abstract class that implements the IDog interface.

Code: Select all

public abstract class DogDecorator : IDog {
    private IDog _dog;
    
    public DogDecorator(IDog dog) {
        _dog = dog;
    }
}
Next we’ll create our decorator from the abstract class that will look up the infractions and calculate the new registration cost.

Code: Select all

public class InfractingDog : DogDecorator {
    public InfractingDog(IDog dog) : 
        this(dog, new DogRepository()) { }

    public InfractingDog(IDog dog, IRepository repository) {

        base(dog);
        _repository = repository;
    }

    private IRepository _repository;

    public int Id {
        get { return _dog.Id; }
        set { _dog.Id = value; }
    }

    public string Name {
        get { return _dogName; }
        set { _dog.Name = value; }
    }

    public string Breed {
        get { return _dog.Breed; }
        set { _dog.Breed = value; }
    }

    public string Address {
        get { return _dog.Address; }
        set { _dog.Address = value; }
    }

    public DateTime RegisterDate {
        get { return _dog.RegisterDate; }
        set { _dog.RegisterDate = value; }
    }

    public int RegistrationCost {
        get {  
            IList<Infraction> infractions = 
                _repository.GetInfractionsByDogId(_dog.Id);

            //increase registration by $5
            //for every infraction
            int extraCost = infractions.Count * 5;

            return _dog.RegistrationCost + extraCost;
        }
    }
}
Final Thoughts
What we have done is wrap our original Dog class in a decorator to add new functionality. By doing it this way we don’t have to worry about breaking any old functionality because we didn’t change the original class. I hope this has demonstrated the Decorator Pattern to you in an easy to understand way that resembles a possible real world situation.

Abstract Factory Pattern
What Is An Abstract Factory?
An abstract factory contains a set of methods that create families of objects. For example you might have a DogFactory class that has various methods for creating different kinds of dogs like CreatePoodle, CreateBeagle, CreateGoldenRetriever, and CreateChocolateLab.

Abstract Class Versus Interface
Before we get too deep into this pattern it is important to note that an abstract class that has only abstract methods is the same as an interface. The benefit of using an abstract class comes when you want to implement functionality in the base class so each derived class doesn’t need to repeat it.

Let’s say you have the following interface.

Code: Select all

public interface ICalculatable {
    int Add(int num1, int num2);
    int Multiply(int num1, int num2);
}
This is a very trivial example but it will be fine for this illustration. If both those methods are going to be the same for each instance of the interface it seems silly to keep repeating the code over and over. It would make more sense to create an abstract class with two non abstract methods so you don’t have to write the code for each instance.

Code: Select all

public abstract class Calculatable {
    public int Add(int num1, int num2) {
        return num1 + num2;
    }

    public int Multiply(int num1, int num2) {
        return num1 * num2;
    }
}
Then you could create multiple concrete classes that inherit from the Calculatable abstract class and not have to write any code for the Add and Multiply methods.

Program Requirements
We’ll be continuing on with our fictional city council that has commissioned us to develop an application that lets them manage their yearly dog registrations. Since the application is all about managing dogs and their owners it makes sense to have a DogFactory class that will create the different breeds of dogs that will be stored in the application.

Our application will have a factory that creates different breeds of dogs and each dog breed will inherit from the IDog interface.

The Pattern
First we’ll setup our abstract factory class that will serve as our contract or interface for a concrete factory class.

Code: Select all

public abstract class AbstractDogFactory {
    public abstract Poodle CreatePoodle();
    public abstract Beagle CreateBeagle();
    public abstract GoldenRetriever CreateGoldenRetriever();
    public abstract ChocolateLab CreateChocolateLab();
}
Then we create a concrete class of our factory contract.

Code: Select all

public class DogFactory : AbstractDogFactory {

    public DogFactory() { }

    public overrride Poodle CreatePoodle() {
        return new Poodle();
    }

    public overrride Beagle CreateBeagle() {
        return new Beagle();
    }

    public overrride GoldenRetriever CreateGoldenRetriever() {
        return new GoldenRetriever();
    }

    public overrride ChocolateLab CreateChocolateLab() {
        return new ChocolateLab();
    }
}
Now we have our factory in place it is very simple to use. Obviously the above implementation is very basic but it illustrates the point.

Code: Select all

AbstractDogFactory dogFactory = new DogFactory();
Poodle mittens = dogFactory.CreatePoodle();
mittens.Name = “Mittens”;
Observer Pattern
What Is The Observer Pattern?
The Observer pattern is a way for an object to notify all of it’s dependants when something changes based on a one to many relationship.

The Situation
Continuing to use our city dog registration software scenario, one of the project’s requirements is that the dog’s owner’s be notified whenever a dog is processed for an infraction (i.e. picked up by the dog catcher). The Observer pattern is perfectly suited to solve this problem.

Setting Up Our Observer
First before we create our Observer we need to define some classes and interfaces that we will need to use with the Observer.

Code: Select all

public interface IInfraction {
    string Type { get; set; }
    int Id { get; set; }
    DateTime Date { get; set; }
    string Reason { get; set; }
    double Fee { get; set; }
}

public class Infraction : IInfraction {
    public string Type { get; set; }

    int Id { get; set; }

    DateTime Date { get; set; }
    string Reason { get; set; }
    double Fee { get; set; }
}

public interface IOwner {
    int Id { get; set; }

    string FirstName { get; set; }

    string LastName { get; set; }

    string EmailAddress { get; set; }
}

public class Owner : IOwner {
    public Owner() { }
    public int Id { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public string EmailAddress { get; set; }

}
The above code defines an infraction and an owner for our Observer to use. Now we can setup our Observer and the notifications when a dog gets an infraction.

Code: Select all

public interface IDog {
    int Id { get; set; }
    string Name { get; set; }
    void AddInfraction(IInfraction infraction);
    void AddOwner(IOwner owner);
}

public class Dog : IDog {
    private IList<IOwner> _owners;
    private IList<IInfraction> _infractions;

    public Dog() { 
        _owners = new List<Owner>();
        _infractions = new List<Infraction>();
    }

    public void AddOwner(IOwner owner) {
        _owners.Add(owner);
    }

    public void AddInfraction(IInfraction infraction) {
        _infractions.Add(infraction);

        //notify owners of infraction : the Observer
        foreach(IOwner owner in _owners) {
            string message = “Dear ” + owner.FirstName + “,\n\n” +
                “We are writing you to inform you that there has been an incident with your dog, “ +
                this.Name + “, and that the city had to get involved.\n\n” +
                “Your dog is being held at the city dog pound for the following reason: “ + infraction.Reason + “.” +
                “You can pick them up anytime. There will be a fee of $” + infraction.Fee + ” applied.”;
            MessageService.SendEmail(owner.EmailAddress, “[email protected]”, message);
        }
    }

    public int Id { get; set; }
    public string Name { get; set; }
}
You can see the this pattern at work in the AddInfraction method. Every time this method is called an infraction is added to the dog’s record and all the owners are sent an email detailing the infraction and where to pick up their dog. It’s nice when you can structure your code to handle situations automatically, for you and your clients.

The Facade Pattern
What Is The Facade Pattern?
The facade pattern is a higher level interface that simplifies and brings together multiple interfaces of a subsystem. What this means is if you want to do something but that requires interacting with multiple subsystems you can create a facade that same only a few methods that handle all the interaction with the subsystem.

Our Application Requirements
In our city dog registration application lets assume there are a few things that need to be done when a new dog is registered. First the new dog and it’s owners must be entered into the system. Next the registration fee must be processed. Finally, we want the system to send the owners the welcome email.

This is a very simple example but this action requires 3 separate systems to do something in order to complete this one task of registering a new dog.

Using The Facade Pattern
For the sake of simplicity and not cluttering this post with too much code, I am not going to provide code for the sub systems, just the facade.

Code: Select all

public class RegistrationManager : IRegister {
    private IAccountingService _accounting;
    private IMessageService _messaging;
    private IRepository = _repository;

    public RegistrationManager(IAccountService accounting, IMessagingService messaging, IRepository repository) {
        _accounting = accounting;
        _messaging = messaging;
        _repository = repository;
    }

    public void RegisterDog(IDog dog) {
        _repository.AddDog(dog);
        _accounting.ProcessPayment(dog.PaymentOrder);
        _messaging.SendWelcome(dog.Owners.Find(x => x.PrimaryContact))
    }
}
As you can see this is a very simple example but it illustrates the concept of the pattern. We have taken 3 tasks, each belonging to a different sub system, and combined them into 1 task in a facade class, in this case the RegistrationManager class.

The RegisterDog method adds the new dog to the repository, sends the payment order to the accounting system, and sends a welcome message to the dogs owners that are flagged as primary contacts.
Summing It Up

I hope this post helps you understand the Facade pattern and I hope you are continuing to learn and have fun with this series.

The Visitor Pattern
What is the visitor pattern?
The visitor design pattern is a way of separating an algorithm from an object structure upon which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying those structures. Thus, using the visitor pattern helps conformance with the open/closed principle.

Our Requirements
One principle that I really like is the Open/Closed principle which says that an object should be open to new functionality but closed to structural changes. The visitor pattern helps facilitate this principle by giving us the means to perform operations against an object without changing the objects structure.

Looking back at a previous pattern we wanted to adjust the registration cost for a dog if they had been picked up by the dog catcher.

Implementing The Visitor
Supposing we have the implementation for the interface below we could use the visitor pattern to perform our tasks without changing the existing classes. Since we won’t be changing the existing implementation we don’t need to worry about breaking existing features. Lets assume that the repository returns 3 infractions for our dog in the code below.

Code: Select all

internal interface IDog {
    int Id { get; set; }
    string Name { get; set; }
    string Breed { get; set; }
    string Address { get; set; }
    DateTime RegisterDate { get; set; }
    int RegistrationCost { get; set; }
    ICollection<Infraction> Infractions { get; }
    void Accept(IVisitor visitor);
}
internal class Dog : IDog {
    private IRepository _repo;


    public Dog(IRepository repo) {
        _repo = repo;
        RegistrationCost = 25;
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Breed { get; set; }
    public string Address { get; set; }
    public DateTime RegisterDate { get; set; }
    public int RegistrationCost { get; set; }
    
    public ICollection<Infraction> Infractions { 
        get { return _repo.GetInfractions(Id); } 
    }

    public void Accept(IVisitor visitor) {
        visitor.Visit(this);
    }
}

internal interface IVisitor {
    void Visit(IDog dog)
}

internal class Visitor : IVisitor {
    public Visitor() { }
    public void Visit(IDog dog) {
        var cost = dog.RegistrationCost;
        var infractions = dog.Infractions.Count;
        //increase cost $5 for each infraction
        dog.RegistrationCost = cost + (infractions * 5);
    }
}
So we have our dog class and we have our visitor setup. All we have left to do is execute it.

Code: Select all

class Program {
    static void Main() {
       IDog dog = new Dog(Repository.Create<IDog>());
            IVisitor visitor = new Visitor();
            dog.Accept(visitor);
            Console.WriteLine(dog.RegistrationCost); //=> 40
   }
}
Conclusion
So just like the Decorator pattern, with the visitor pattern we can modify our class without changing the classes code. This pattern is more flexible because we can create any number of visitor classes to do just about anything without changing any code.
Post Reply

Return to “.NET Programming”