NashTech Blog

Table of Contents
woman sharing her presentation with her colleagues

Design Patterns In C#

Design patterns provide general solutions or a flexible way to solve common design problems. Here we will discuss design patterns and explore their implementation in C# and .NET.

First let’s understand the meaning of design patterns and why they are useful in software architecture and programming.

What are Design Patterns in Software Development?

Design patterns in .NET are solutions to recurring problems in software design. They provide reusable templates for how to solve common issues that developers face when designing applications. It provides a template or description of how to solve problems applicable in many situations.

A pattern is a recurring solution to a problem in a context.

Each pattern describes a problem that occurs over and over again in our environment and then describes the core of the solution to that problem in such a way that you can use this solution a million times over without ever doing it the same way twice.” – Christopher Alexander, A Pattern Language.

Broadly, Design Patterns are divided into 3 categories, comprising a total of 23 design patterns.

  1. Creational Design Pattern
  2. Structural Design Patterns
  3. Behavioral Design Patterns

Here are some commonly used design patterns in .NET

     1. Singleton Pattern: Ensures that a class has only one instance and provides a global point of access to that instance. It is a Creational Design pattern.

public class Singleton
{
private static Singleton instance;

// Private constructor to prevent instantiation from outside
private Singleton() { }

// Public static method to get the singleton instance
public static Singleton GetInstance()
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}

// Example method
public void PrintMessage()
{
Console.WriteLine("Singleton instance is working!");
}
}
Usage:
Singleton singleton1 = Singleton.GetInstance();
Singleton singleton2 = Singleton.GetInstance();

// Both singleton1 and singleton2 will refer to the same instance

singleton1.PrintMessage(); // Output: Singleton instance is working!
singleton2.PrintMessage(); // Output: Singleton instance is working!

      2. Factory Method Pattern: Defines an interface for creating an object, but allows subclasses to alter the type of objects that will be created. It is a Creational Design pattern.

// Product interface
public interface IProduct
{
void Use();
}

// Concrete product
public class ConcreteProduct : IProduct
{
public void Use()
{
Console.WriteLine("Using concrete product...");
}
}

// Creator interface
public interface ICreator
{
IProduct FactoryMethod();
}

// Concrete creator
public class ConcreteCreator : ICreator
{
public IProduct FactoryMethod()
{
return new ConcreteProduct();
}
}
Usage:
ICreator creator = new ConcreteCreator();
IProduct product = creator.FactoryMethod();
product.Use(); // Output: Using concrete product...


3. Abstract Factory Pattern:
Provides an interface for creating families of related or dependent objects without specifying their concrete classes. In .NET, you can define an   abstract factory interface with methods for creating related objects, and then implement concrete factory classes for different product families.

// Abstract product A
public interface IProductA
{
void MethodA();
}

// Concrete product A1
public class ConcreteProductA1 : IProductA
{
public void MethodA()
{
Console.WriteLine("Executing method A from product A1.");
}
}

// Concrete product A2
public class ConcreteProductA2 : IProductA
{
public void MethodA()
{
Console.WriteLine("Executing method A from product A2.");
}
}

// Abstract product B
public interface IProductB
{
void MethodB();
}

// Concrete product B1
public class ConcreteProductB1 : IProductB
{
public void MethodB()
{
Console.WriteLine("Executing method B from product B1.");
}
}

// Concrete product B2
public class ConcreteProductB2 : IProductB
{
public void MethodB()
{
Console.WriteLine("Executing method B from product B2.");
}
}

// Abstract factory
public interface IAbstractFactory
{
IProductA CreateProductA();
IProductB CreateProductB();
}

// Concrete factory 1
public class ConcreteFactory1 : IAbstractFactory
{
public IProductA CreateProductA()
{
return new ConcreteProductA1();
}

public IProductB CreateProductB()
{
return new ConcreteProductB1();
}
}

// Concrete factory 2
public class ConcreteFactory2 : IAbstractFactory
{
public IProductA CreateProductA()
{
return new ConcreteProductA2();
}

public IProductB CreateProductB()
{
return new ConcreteProductB2();
}
}
Usage :
// Client code using abstract factory
IAbstractFactory factory1 = new ConcreteFactory1();
IProductA productA1 = factory1.CreateProductA();
IProductB productB1 = factory1.CreateProductB();

productA1.MethodA(); // Output: Executing method A from product A1.
productB1.MethodB(); // Output: Executing method B from product B1.

IAbstractFactory factory2 = new ConcreteFactory2();
IProductA productA2 = factory2.CreateProductA();
IProductB productB2 = factory2.CreateProductB();

productA2.MethodA(); // Output: Executing method A from product A2.
productB2.MethodB(); // Output: Executing method B from product B2.

4. Builder Pattern: Separates the construction of a complex object from its representation, allowing the same construction process to create different representations. In .NET, we can use a builder interface to define the construction steps, and concrete builder classes to implement them.

// Product
public class Product
{
public string Part1 { get; set; }
public string Part2 { get; set; }

public void Display()
{
Console.WriteLine($"Part 1: {Part1}, Part 2: {Part2}");
}
}

// Builder interface
public interface IBuilder
{
void BuildPart1();
void BuildPart2();
Product GetResult();
}

// Concrete builder
public class ConcreteBuilder : IBuilder
{
private Product product = new Product();

public void BuildPart1()
{
product.Part1 = "Part 1 built";
}

public void BuildPart2()
{
product.Part2 = "Part 2 built";
}

public Product GetResult()
{
return product;
}
}

// Director
public class Director
{
public void Construct(IBuilder builder)
{
builder.BuildPart1();
builder.BuildPart2();
}
}


Usage:
// Client code using builder
IBuilder builder = new ConcreteBuilder();
Director director = new Director();
director.Construct(builder);

Product product = builder.GetResult();
product.Display(); // Output: Part 1: Part 1 built, Part 2: Part 2 built

The above examples illustrate how to implement design patterns in C#/.NET. They provide solutions to common problems such as ensuring only one instance of a class exists (Singleton) and allowing subclasses to create instances of objects without specifying their exact types (Factory Method). Additionally, they showcase approaches for creating families of related objects with a common interface (Abstract Factory) and for constructing complex objects step by step (Builder).

Picture of Ajay Jajoo

Ajay Jajoo

Leave a Comment

Your email address will not be published. Required fields are marked *

Suggested Article

Scroll to Top