Design Patterns In .NET

Introduction

 
So basically, what are design patterns? We can define design patterns as proven techniques to achieve certain tasks. They give us a basic template to design our application using templates that have been proven to meet the requirements of performance, maintainability, extensibility, scalability and security. Object oriented programming is the backbone of software development these days and this holds  true for C# development as well. Design Patterns: Elements of Reusable Object-Oriented Software (1994) is a software engineering book which describes software design patterns. The book was written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, with a foreword by Grady Booch. It describes 23 classic software design patterns and is regarded as an important source for object-oriented design theory and practice. The authors are often referred to as the Gang of Four (GoF). This book includes examples in C++ and Smalltalk. These design patterns have been divided into three categories and in this article, I will provide two samples from each category in C#.

The 3 Categories and 23 Design Patterns

 
For a complete list of all the 23 Design Patterns, you can visit the link (The Gang of Four Design Patterns). In this article I will discuss two design patterns from each category which are below,
 
Creational Design Patterns
 
Creational patterns help us with creating objects in a flexible manner according to our requirements
  1. Singleton pattern – Only allows one instance of a class.
  2. Factory pattern - Creates objects based on an input parameter.
Structural Design Patterns
 
Structural patterns help us design interfaces and use inheritance to design functionality in our applications.
  1. Adapter pattern – Provides a link between classes that have incompatible interfaces
  2. Facade pattern - Provides a simplified interface to some complex classes
Behavioral Design Patterns
 
Behavioral patterns are mostly linked to communications between objects in our application.
  1. Observer pattern – This is a publisher-subscriber pattern which allows the publisher to publish events and subscribers to subscribe and act upon these events
  2. Template pattern – This provides a layout of a base class which is then used by several classes
We will now look at these six design patterns one by one with examples.
 

The Singleton Pattern

 
Below is a class designed using the singleton pattern,
  1. namespace DesignPatterns  
  2. {  
  3.     public class SingletonClass  
  4.     {  
  5.         private int number = 100;  
  6.   
  7.         private static SingletonClass _instance;  
  8.         public static SingletonClass Instance  
  9.         {  
  10.             get  
  11.             {  
  12.                 _instance = (_instance ?? new SingletonClass());  
  13.                 return _instance;  
  14.             }  
  15.         }  
  16.   
  17.         public int GetSingletonValue()  
  18.         {  
  19.             return ++number;  
  20.         }  
  21.     }  
  22.   
  23. }  
We can call the class using the below code, 
  1. // Singleton Pattern testing  
  2. var singletonClassValueOne = SingletonClass.Instance.GetSingletonValue();  
  3. Console.WriteLine($"First Read value is {singletonClassValueOne}");  
  4.   
  5. var singletonClassValueTwo = SingletonClass.Instance.GetSingletonValue();  
  6. Console.WriteLine($"First Read value is {singletonClassValueTwo}");  
When we run this application, we see the below results,
 
Design Patterns In .NET
 
Hence, we see that only one instance of the class is created and that is the first time this class is called. After that, the existing instance is used.
 

The Factory Pattern

 
Below is a class designed using the Factory pattern,
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4.   
  5. namespace DesignPatterns  
  6. {  
  7.     // The main classes interface  
  8.     public interface IThermostat  
  9.     {  
  10.         void Control();  
  11.     }  
  12.   
  13.     // The Cooling Thermostat class  
  14.     public class CoolingThermostat : IThermostat  
  15.     {  
  16.         private readonly double _temp;  
  17.         public CoolingThermostat(double temp)  
  18.         {  
  19.             _temp = temp;  
  20.         }  
  21.         public void Control()  
  22.         {  
  23.             Console.WriteLine($"Cooling the house to {_temp} degrees");  
  24.         }  
  25.     }  
  26.   
  27.     // The Warming Thermostat class  
  28.     public class WarmingThermostat : IThermostat  
  29.     {  
  30.         private readonly double _temp;  
  31.         public WarmingThermostat(double temp)  
  32.         {  
  33.             _temp = temp;  
  34.         }  
  35.         public void Control()  
  36.         {  
  37.             Console.WriteLine($"Warming the house to {_temp} degrees");  
  38.         }  
  39.     }  
  40.   
  41.     // The Factory classes  
  42.     public abstract class ThemostatFactory  
  43.     {  
  44.         public abstract IThermostat Create(double temp);  
  45.     }  
  46.   
  47.     public class CoolingThermostatFactory : ThemostatFactory  
  48.     {  
  49.         public override IThermostat Create(double temp) => new CoolingThermostat(temp);  
  50.     }  
  51.     public class WarmingThermostatFactory : ThemostatFactory  
  52.     {  
  53.         public override IThermostat Create(double temp) => new WarmingThermostat(temp);  
  54.     }  
  55.   
  56.     // Implementing the Factory  
  57.   
  58.     public enum Actions  
  59.     {  
  60.         Cooling,  
  61.         Warming  
  62.     }  
  63.   
  64.     public class Thermostat  
  65.     {  
  66.         private readonly Dictionary<Actions, ThemostatFactory> _factories;  
  67.           
  68.         public Thermostat()  
  69.         {  
  70.             _factories = new Dictionary<Actions, ThemostatFactory>();  
  71.             foreach(Actions action in Enum.GetValues(typeof(Actions)))  
  72.             {  
  73.                 var factory = (ThemostatFactory)Activator.CreateInstance(Type.GetType("DesignPatterns." + Enum.GetName(typeof(Actions),action) + "ThermostatFactory"));  
  74.                 _factories.Add(action, factory);  
  75.             }  
  76.         }  
  77.   
  78.         public IThermostat ExecuteCreate(Actions action, double temp) => _factories[action].Create(temp);  
  79.     }  
  80.   
  81. }  
We can call the class using the below code,
  1. //// Factory Pattern testing  
  2. var factory = new Thermostat().ExecuteCreate(Actions.Cooling, 17.5);  
  3. factory.Control();  
  4.   
  5. factory = new Thermostat().ExecuteCreate(Actions.Warming, 21.5);  
  6. factory.Control();  
When we run this application, we see the below results,
 
Design Patterns In .NET
 
Here we see that we pass the Enum value of the class and get back an instance of the class instead of explicitly creating a class.

The Adapter Pattern

 
Below is a class designed using the Adapter pattern,
  1. using System;  
  2. using System.Collections.Generic;  
  3.   
  4. namespace DesignPatterns  
  5. {  
  6.     public class LocalEmployeeSystem  
  7.     {  
  8.         private ISource _employeeAdapter;  
  9.   
  10.         public LocalEmployeeSystem(ISource employeeAdapter)  
  11.         {  
  12.             this._employeeAdapter = employeeAdapter;  
  13.         }  
  14.   
  15.         public void ShowEmployeeList()  
  16.         {  
  17.             List<string> employees = _employeeAdapter.GetEmployeeList();  
  18.             // Modify list and apply business logic  
  19.   
  20.             foreach (var employee in employees)  
  21.             {  
  22.                 Console.Write(employee);  
  23.             }  
  24.         }  
  25.     }  
  26.   
  27.     public interface ISource  
  28.     {  
  29.         List<string> GetEmployeeList();  
  30.     }  
  31.   
  32.     public class BIEmployeeSystem  
  33.     {  
  34.         public string[][] GetEmployees()  
  35.         {  
  36.             string[][] employees = new string[2][];  
  37.   
  38.             employees[0] = new string[] { "100""John Doe""Director" };  
  39.             employees[1] = new string[] { "101""Jane Doe""Manager" };  
  40.   
  41.             return employees;  
  42.         }  
  43.     }  
  44.   
  45.     public class EmployeeAdapter : ISource  
  46.     {  
  47.         public List<string> GetEmployeeList()  
  48.         {  
  49.             List<string> employeeList = new List<string>();  
  50.   
  51.             var BiEmployeeSystem = new BIEmployeeSystem();  
  52.   
  53.             string[][] employees = BiEmployeeSystem.GetEmployees();  
  54.             foreach (string[] employee in employees)  
  55.             {  
  56.                 employeeList.Add($"{employee[0]},{employee[1]},{employee[2]} \n");  
  57.             }  
  58.   
  59.             return employeeList;  
  60.         }  
  61.     }  
  62. }  
We can call the class using the below code,
  1. // Adapter Pattern testing  
  2. var source = new EmployeeAdapter();  
  3. var client = new LocalEmployeeSystem(source);  
  4. client.ShowEmployeeList();  
When we run this application, we see the below results,
 
Design Patterns In .NET
 
Here we see that the Employee Adapter class converts the array of string from the BIEmployeeSystem class to a list of string which is required by the LocalEmployeeSystem class.

The Facade Pattern

 
Below is a class designed using the Facade pattern,
  1. namespace DesignPatterns  
  2. {  
  3.     internal class EmployeePersonalDetails  
  4.     {  
  5.         internal int ID;  
  6.         internal string FirstName;  
  7.         internal string LastName;  
  8.         internal string Address;  
  9.         internal string ContactNumber;  
  10.         internal int Age;  
  11.   
  12.         public EmployeePersonalDetails(int Id)  
  13.         {  
  14.             // Load the Employee data for provided Id  
  15.             // We will hard code here  
  16.   
  17.             ID = 1;  
  18.             FirstName = "John";  
  19.             LastName = "Doe";  
  20.             Address = "100 Street West, Toronto, ON, Canada";  
  21.             ContactNumber = "100-100-100";  
  22.             Age = 35;  
  23.         }  
  24.     }  
  25.   
  26.     internal class EmployeeSalaryDetails  
  27.     {  
  28.         internal int ID;  
  29.         internal double BaseSalary;  
  30.         internal double Tax;  
  31.   
  32.         public EmployeeSalaryDetails(int Id)  
  33.         {  
  34.             // Load the Employee data for provided Id  
  35.             // We will hard code here  
  36.   
  37.             ID = 1;  
  38.             BaseSalary = 3000.00;  
  39.             Tax = 300.75;  
  40.         }  
  41.     }  
  42.   
  43.     public class EmployeeDetails  
  44.     {  
  45.         public int ID { getprivate set; }  
  46.         public string FullName { getprivate set; }  
  47.         public string Address { getprivate set; }  
  48.         public string ContactNumber { getprivate set; }  
  49.         public double NetPay { getprivate set; }  
  50.   
  51.         public EmployeeDetails(int id)  
  52.         {  
  53.             var _employeePersonalDetails = new EmployeePersonalDetails(id);  
  54.             var _employeeSalaryDetails = new EmployeeSalaryDetails(id);  
  55.             ID = id;  
  56.             FullName = $"{_employeePersonalDetails.FirstName} {_employeePersonalDetails.LastName}";  
  57.             Address = _employeePersonalDetails.Address;  
  58.             ContactNumber = _employeePersonalDetails.ContactNumber;  
  59.             NetPay = _employeeSalaryDetails.BaseSalary - _employeeSalaryDetails.Tax;  
  60.         }  
  61.   
  62.     }  
  63. }  
We can call the class using the below code,
  1. // Facade Pattern testing  
  2. var EmployeeDetails = new EmployeeDetails(100);  
  3. Console.WriteLine($"Employee ID is {EmployeeDetails.ID}");  
  4. Console.WriteLine($"Name is {EmployeeDetails.FullName}");  
  5. Console.WriteLine($"Address is {EmployeeDetails.Address}");  
  6. Console.WriteLine($"Contact Number is {EmployeeDetails.ContactNumber}");  
  7. Console.WriteLine($"Net Pay is {EmployeeDetails.NetPay}");  
When we run this application, we see the below results,
 
Design Patterns In .NET
 
Here we see that we collect the data from two classes and present it through a third class, which is the façade class, as it is just a point to collect more complex data and present it.
 

The Observer Pattern

 
Below is a class designed using the Observer pattern,
  1. using System;  
  2. using System.Collections;  
  3.   
  4. namespace DesignPatterns  
  5. {  
  6.     public abstract class Publisher  
  7.     {  
  8.         private ArrayList observers = new ArrayList();  
  9.   
  10.         public void AddObserver(IObserver o)  
  11.         {  
  12.             observers.Add(o);  
  13.         }  
  14.   
  15.         public void RemoveObserver(IObserver o)  
  16.         {  
  17.             observers.Remove(o);  
  18.         }  
  19.   
  20.         public void NotifyObservers()  
  21.         {  
  22.             foreach (IObserver o in observers)  
  23.             {  
  24.                 o.Update();  
  25.             }  
  26.         }  
  27.     }  
  28.   
  29.     public class UsablePublisher : Publisher  
  30.     {  
  31.         private string value;  
  32.   
  33.         public string GetValue()  
  34.         {  
  35.             return value;  
  36.         }  
  37.   
  38.         public void SetValue(string newValue)  
  39.         {  
  40.             value = newValue;  
  41.             NotifyObservers();  
  42.         }  
  43.     }  
  44.   
  45.     public interface IObserver  
  46.     {  
  47.         void Update();  
  48.     }  
  49.   
  50.     public class UsedObserver : IObserver  
  51.     {  
  52.         private UsablePublisher publisher;  
  53.   
  54.         public UsedObserver(UsablePublisher pub)  
  55.         {  
  56.             publisher = pub;  
  57.         }  
  58.   
  59.         public void Update()  
  60.         {  
  61.             Console.WriteLine($"The updated value is { publisher.GetValue()}");  
  62.         }  
  63.     }  
  64. }  
We can call the class using the below code,
  1. // Observer Pattern  
  2. var usablePublisher = new UsablePublisher();  
  3. var usedObserver = new UsedObserver(usablePublisher);  
  4. usablePublisher.AddObserver(usedObserver);  
  5. usablePublisher.SetValue("Updated Value!");  
When we run this application, we see the below results,
 
Design Patterns In .NET
 
Hence, we see that when the value is changed, the publisher notifies all observers and they take appropriate action, as required.
 

The Template Pattern

 
Below is a class designed using the Template pattern,
  1. using System;  
  2.   
  3. namespace DesignPatterns  
  4. {  
  5.     public abstract class WriteArticle  
  6.     {  
  7.         public WriteArticle()  
  8.         {  
  9.             Introduction();  
  10.             MainBody();  
  11.             Examples();  
  12.             Summary();  
  13.         }  
  14.         public abstract void Introduction();  
  15.         public abstract void MainBody();  
  16.         public abstract void Examples();  
  17.         public abstract void Summary();  
  18.   
  19.     }  
  20.   
  21.     public class ArticleA : WriteArticle  
  22.     {  
  23.   
  24.         public override void Introduction()  
  25.         {  
  26.             Console.WriteLine($"This is the introduction section of Article A");  
  27.         }  
  28.   
  29.         public override void MainBody()  
  30.         {  
  31.             Console.WriteLine($"This is the main body section of Article A");  
  32.         }  
  33.   
  34.         public override void Examples()  
  35.         {  
  36.             Console.WriteLine($"These are examples of Article A");  
  37.         }  
  38.   
  39.         public override void Summary()  
  40.         {  
  41.             Console.WriteLine($"This is the summary section of Article A");  
  42.         }  
  43.     }  
  44.     public class ArticleB : WriteArticle  
  45.     {  
  46.         public override void Introduction()  
  47.         {  
  48.             Console.WriteLine($"This is the introduction section of Article B");  
  49.         }  
  50.   
  51.         public override void MainBody()  
  52.         {  
  53.             Console.WriteLine($"This is the main body section of Article B");  
  54.         }  
  55.   
  56.         public override void Examples()  
  57.         {  
  58.             Console.WriteLine($"These are examples of Article B");  
  59.         }  
  60.   
  61.         public override void Summary()  
  62.         {  
  63.             Console.WriteLine($"This is the summary section of Article B");  
  64.         }  
  65.     }  
  66. }  
We can call the class using the below code,
  1. // Template pattern  
  2. var articleA = new ArticleA();  
  3. var articleB = new ArticleB();  
When we run this application, we see the below results,
 
Design Patterns In .NET
 
In this pattern, we design a layout of some actions and then each class that inherits from it, provides its own implementation, as required.
 

Summary

 
In this article, we have looked at 6 design patterns, two from each of the creational, structural and behavioral categories. We see that these templates provide a starting point for us to design our classes for a particular requirement. I would recommend you look at the remaining design patterns as well and try to implement these in your object-oriented applications.


Recommended Free Ebook
Similar Articles