Skip to content

Instantly share code, notes, and snippets.

@ernitingarg
Last active May 29, 2024 13:49
Show Gist options
  • Save ernitingarg/179a443096752c84353853b9d303373e to your computer and use it in GitHub Desktop.
Save ernitingarg/179a443096752c84353853b9d303373e to your computer and use it in GitHub Desktop.
Design Patterns

Factory Method Design Pattern

GOF Definition:

Define an interface for creating an object, but let subclasses decide which class to instantiate.

Definition:

The Factory Design Pattern is a creational design pattern that provides an interface for creating objects but allows subclasses to decide the type of objects that will be created. It's useful when you have a superclass with multiple subclasses and you want to delegate the responsibility of object creation to these subclasses.

It encapsulates object creation and abstracts it from the client code, promoting loose coupling between the client and the created objects.

image

Example:

// Abstract product
public interface IProduct
{
    void Init();
    void Execute();
    void Cleanup();
}

public class ConcreteProductA : IProduct
{
    public void Init()
    {
        Console.WriteLine("Initializing Concrete Product A.");
    }

    public void Execute()
    {
        Console.WriteLine("Executing Concrete Product A.");
    }

    public void Cleanup()
    {
        Console.WriteLine("Cleaning up Concrete Product A.");
    }
}


public class ConcreteProductB : IProduct
{
    public void Init()
    {
        Console.WriteLine("Initializing Concrete Product B.");
    }

    public void Execute()
    {
        Console.WriteLine("Executing Concrete Product B.");
    }

    public void Cleanup()
    {
        Console.WriteLine("Cleaning up Concrete Product B.");
    }
}

// Create a Simple Factory class that encapsulates the object creation logic.
public class SimpleFactory
{
    public IProduct CreateProduct(string productType)
    {
        // Depending on the productType parameter, create and return a specific product.
        switch (productType)
        {
            case "A":
                return new ConcreteProductA();
            case "B":
                return new ConcreteProductB();
            default:
                throw new ArgumentException("Invalid product type");
        }
    }
}

// Client code
class Program
{
    static void Main()
    {
        // Create a SimpleFactory object.
        SimpleFactory factory = new SimpleFactory();

        // Use the factory to create products.
        IProduct productA = factory.CreateProduct("A");
        productA.Init();
        productA.Execute();
        productA.Cleanup();

        IProduct productB = factory.CreateProduct("B");
        productB.Init();
        productB.Execute();
        productB.Cleanup();
    }
}

Abstract Factory Design Pattern

GOF Definition:

Provide an interface for creating families of related or dependent objects without specifying their concrete classes

Definition:

The Abstract Factory design pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. It allows you to create objects that belong to a certain family of classes without needing to know the exact classes you're instantiating.

This pattern is also called as Factory of factories.

image

Example:

// Bike product
public interface IBike
{
    string GetName();
}

class RegularBike : IBike
{
    public string GetName()
    {
        return "Regular Bike";
    }
}

class SportBike : IBike
{
    public string GetName()
    {
        return "Sport Bike";
    }
}

// Car product
public interface ICar
{
    string GetName();
}

class RegularCar : ICar
{
    public string GetName()
    {
        return "Regular Car";
    }
}

class SportCar : ICar
{
    public string GetName()
    {
        return "Sport Car";
    }
}

// Vehicle Factory
public interface IVehicleFactory
{
    IBike CreateBike(string type);
    ICar CreateCar(string type);
}

// Hero factory for car and bike
class HeroFactory : IVehicleFactory
{
    public IBike CreateBike(string type)
    {
        if (type == "sport")
        {
            return new SportBike();
        }

        return new RegularBike();
    }

    public ICar CreateCar(string type)
    {
        if (type == "sport")
        {
            return new SportCar();
        }

        return new RegularCar();
    }
}

// Honda factory for car and bike
class HondaFactory : IVehicleFactory
{
    public IBike CreateBike(string type)
    {
        if (type == "sport")
        {
            return new SportBike();
        }

        return new RegularBike();
    }

    public ICar CreateCar(string type)
    {
        if (type == "sport")
        {
            return new SportCar();
        }

        return new RegularCar();
    }
}

//Vehicle factory for hero and honda
public static class VehicleFactory
{
    public static IVehicleFactory GetFactory(string type)
    {
        if (type == "hero")
        {
            return new HeroFactory();
        }

        return new HondaFactory();
    }
}

// Client code
public void Main()
{
    IVehicleFactory heroFactory = VehicleFactory.GetFactory("hero");
    
    IBike bike = heroFactory.CreateBike("sport");
    ICar car = heroFactory.CreateCar("regular");

    Console.WriteLine(bike.GetName()); // Output: Sport Bike
    Console.WriteLine(car.GetName());  // Output: Regular Car
}

Builder Design Pattern

GOF Definition:

Separate the construction of a complex object from its representation so that the same construction process can create different representations

Definition:

The Builder design pattern is a creational design pattern that separates the construction of a complex object from its representation. It allows you to create a complex object step by step. This pattern is particularly useful when you need to create an object with many optional attributes or configurations.

image

Example:

// The Product class represents the complex object we want to build.
class Product
{
    public string Part1 { get; set; }
    public string Part2 { get; set; }
    public string Part3 { get; set; }
}

// The Builder interface defines the steps to construct the product.
interface IBuilder
{
    void BuildPart1();
    void BuildPart2();
    void BuildPart3();
    Product GetProduct();
}

// A concrete builder class that implements the IBuilder interface.
class ConcreteBuilder : IBuilder
{
    private Product product = new Product();

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

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

    public void BuildPart3()
    {
        product.Part3 = "Part 3 of the product";
    }

    public Product GetProduct()
    {
        return product;
    }
}

// The Director class controls the construction process using a builder.
class Director
{
    private IBuilder builder;

    public Director(IBuilder builder)
    {
        this.builder = builder;
    }

    public void Construct()
    {
        builder.BuildPart1();
        builder.BuildPart2();
        builder.BuildPart3();
    }
    
    public Product GetProduct()
    {
        return builder.GetProduct();
    }
}

// Client code
class Program
{
    static void Main()
    {
        // Create a concrete builder
        IBuilder builder = new ConcreteBuilder();

        // Create a director and associate it with the builder
        Director director = new Director(builder);

        // Construct the product
        director.Construct();

        // Get the final product
        var product = director.GetProduct();
    }
}

Prototype Design Pattern

GOF Definition:

A fully initialized instance to be copied or cloned

Definition:

The Prototype design pattern is a creational pattern that allows you to create new objects by copying/cloning an existing object, known as the prototype. This pattern is useful when creating an object is more expensive or complex than copying an existing one.
It can help improve the performance of the application and reduce the complexity of object creation.

In C#, The Prototype Design Pattern can be implemented using either shallow copy (shares references to nested objects) or a deep copy (creates new instances of nested objects).

image

Example:

// The prototype interface
interface IPrototype
{
    IPrototype Clone();
}

// Concrete prototype class
// [Serializable] // Mark the class as serializable if object needs to be cloned using MemoryStream
class ConcretePrototype : IPrototype
{
    public int Id { get; set; }
    public string Name { get; set; }

    public ConcretePrototype(int id, string name)
    {
        Id = id;
        Name = name;
    }

    public IPrototype Clone()
    {
        // Shallow copy
        return (IPrototype)MemberwiseClone();
        
        // Deep copy
        /*
            // Perform a deep copy for non-serializable objects
            return new ConcretePrototype(2, "New Object");
        */
        
        /*
            // Perform a deep copy using MemoryStream for serializable objects
            using (MemoryStream memoryStream = new MemoryStream())
            {
                // Create a formatter for binary serialization
                IFormatter formatter = new BinaryFormatter();

                // Serialize the current object to the memory stream
                formatter.Serialize(memoryStream, this);

                // Reset the memory stream position
                memoryStream.Seek(0, SeekOrigin.Begin);

                // Deserialize and return the cloned object
                return (IPrototype)formatter.Deserialize(memoryStream);
            }
        */
    }
}

// Client code
class Program
{
    static void Main(string[] args)
    {
        // Creating a prototype instance
        ConcretePrototype original = new ConcretePrototype(1, "Original Object");

        // Cloning the prototype
        ConcretePrototype clone = (ConcretePrototype)original.Clone();

        // Modifying the cloned object
        clone.Name = "Cloned Object";

        Console.WriteLine($"Original: {original.Id} - {original.Name}");
        Console.WriteLine($"Clone: {clone.Id} - {clone.Name}");
    }
}

Singleton Design Pattern

GOF Definition:

The Singleton design pattern ensures a class has only one instance and provide a global point of access to it.

Definition:

The Singleton design pattern is a creational design pattern that ensures a class has only one instance and provides a global point of access to that instance. This can be useful when you want to ensure that there is a single instance of a class throughout the lifetime of an application, such as managing a configuration manager or a database connection pool.

image

Example:

// Thread safe early instance creation (eager initialization)
public sealed class Singleton
{
    // static initializers are thread safe, so CLR will take care for keeping it thread safe.
    private static Singleton instance = new Singleton();
   
    // Private constructor to prevent instantiation from other classes.
    private Singleton()
    {
        Console.WriteLine("Singleton instance created.");
    }

    // Public method to access the Singleton instance.
    public static Singleton GetInstance()
    {
        return instance;
    }
}

// Thread-safe lazy initialization using Double-checked Locking
public sealed class Singleton
{
    private static Singleton instance = null;
    private static readonly object lockObject = new object();

    // Private constructor to prevent instantiation from other classes.
    private Singleton()
    {
        Console.WriteLine("Singleton instance created.");
    }

    // Public method to access the Singleton instance.
    public static Singleton GetInstance()
    {
        // Double-check locking for thread safety.
        if (instance == null)
        {
            lock (lockObject)
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

// Thread safe lazy initialization using Lazy<T> type
public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());
    
    // Private constructor to prevent instantiation from other classes.
    private Singleton()
    {
        Console.WriteLine("Singleton instance created.");
    }

    // Public method to access the Singleton instance.
    public static Singleton GetInstance()
    { 
        return lazy.Value; 
    }
}

// Thread safe and fully Lazy Instantiation using nested class
public sealed class Singleton
{    
    // Private constructor to prevent instantiation from other classes.
    private Singleton()
    {
        Console.WriteLine("Singleton instance created.");
    }

    // Public method to access the Singleton instance.
    public static Singleton GetInstance()
    { 
        return Nested.instance; 
    }
           
    private class Nested
    {
        internal static readonly Singleton instance = new Singleton();
    }
}

// Client code
class Program
{
    static void Main(string[] args)
    {
        Singleton instance1 = Singleton.Instance;
        Singleton instance2 = Singleton.Instance;

        // Both instances should be the same.
        Console.WriteLine("Are both instances the same? " + (instance1 == instance2)); // Should print "True"
    }
}

Adapter Design Pattern

GOF Definition:

The Adapter pattern allows a system to use classes of another system that is incompatible with it.

Definition:

The Adapter Design Pattern is a structural design pattern that allows objects with incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces, making them compatible without changing their existing code.

image

Example:

// Existing class with an incompatible interface
public class OldSystem
{
    public void DoSomethingOld()
    {
        Console.WriteLine("Doing something the old way.");
    }
}

// New interface expected by the client code
public interface INewSystem
{
    void DoSomethingNew();
}

// Adapter class that adapts the OldSystem to the INewSystem interface
public class OldSystemAdapter : INewSystem
{
    private OldSystem oldSystem;

    public OldSystemAdapter()
    {
        oldSystem = new OldSystem();
    }

    public void DoSomethingNew()
    {
        oldSystem.DoSomethingOld(); // Delegates to the old system
    }
}

// Client code using the new system interface
class Program
{
    static void Main()
    {
        INewSystem newSystem = new OldSystemAdapter();
        newSystem.DoSomethingNew(); // Calls OldSystem's method through the adapter.
    }
}

Bridge Design Pattern

GOF Definition:

Decouple an abstraction from its implementation so that the two can vary independently.

Definition:

The Bridge Design Pattern is a structural design pattern that separates an object's abstraction from its implementation, allowing them to vary independently. It allows you to create two separate hierarchies, one for abstraction and one for implementation, and then connect them using a bridge interface.

This pattern is useful when you want to decouple the abstraction and implementation hierarchies, allowing them to evolve separately.

image

Example:

// First hierarchy
// Abstraction: This is the abstract message class that uses IMessageSender to send messages.
public abstract class Message
{
    protected IMessageSender messageSender;

    public Message(IMessageSender sender)
    {
        this.messageSender = sender;
    }

    // This is an abstract method to send a message.
    public abstract void Send();
}

public class TextMessage : Message
{
    public TextMessage(IMessageSender sender) : base(sender) { }

    public override void Send()
    {
        Console.WriteLine("Preparing the text message...");
        messageSender.SendMessage("Hello via text message!");
    }
}

public class EmailMessage : Message
{
    public EmailMessage(IMessageSender sender) : base(sender) { }

    public override void Send()
    {
        Console.WriteLine("Composing the email message...");
        messageSender.SendMessage("Hello via email!");
    }
}

// Second hierarchy
// Implementations: These are the different ways to send messages.
public interface IMessageSender
{
    void SendMessage(string message);
}

public class EmailSender : IMessageSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine($"Sending an email: {message}");
    }
}

public class MsmqSender : IMessageSender
{
    public void SendMessage(string message)
    {
        Console.WriteLine($"Sending a message via MSMQ: {message}");
    }
}

// Client code
public class Program
{
    static void Main(string[] args)
    {
        // Create instances of senders (implementations)
        IMessageSender emailSender = new EmailSender();
        IMessageSender msmqSender = new MsmqSender();

        // Create instances of message types (abstractions) with specific senders (associate them using bridge)
        Message textMessage = new TextMessage(emailSender);
        Message emailMessage = new EmailMessage(msmqSender);

        // Send messages using the abstractions
        textMessage.Send();
        emailMessage.Send();
    }
}

Composite Design Pattern

GOF Definition:

Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.

Definition:

Composite pattern is used when we need to treat a group of objects and a single object in the same way. It is especially useful when you have a hierarchical structure of objects and you want to perform operations on individual objects and their compositions without distinguishing between them.

image

Example:

// Component interface
interface IFileSystem
{
    void Display();
}

// Leaf class (file)
class File : IFileSystem
{
    private string name;

    public File(string name)
    {
        this.name = name;
    }

    public void Display()
    {
        Console.WriteLine($"File: {name}\n");
    }
}

// Composite class (folder)
class Folder : IFileSystem
{
    private string name;
    private List<IFileSystem> items = new List<IFileSystem>();

    public Folder(string name)
    {
        this.name = name;
    }

    public void AddItem(IFileSystem item)
    {
        items.Add(item);
    }

    public void Display()
    {
        Console.WriteLine($"Folder: {name}\n");
        foreach (var item in items)
        {
            item.Display();
        }
    }
}

// Client code
class Program
{
    static void Main(string[] args)
    {
        // Creating files
        File file1 = new File("file1.txt");
        File file2 = new File("file2.txt");

        // Creating subfolder and adding files
        Folder subfolder = new Folder("Subfolder");
        subfolder.AddItem(file1);
        subfolder.AddItem(file2);

        // Creating the root folder and adding subfolder and files
        Folder rootFolder = new Folder("Root");
        rootFolder.AddItem(subfolder);

        // Displaying the folder and file hierarchy
        // (Operation is performed uniformly)
        Console.WriteLine("Folder and File Hierarchy:");
        rootFolder.Display("");
    }
}

Decorator Design Pattern

GOF Definition:

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.

Definition:

The Decorator design pattern is a structural design pattern that allows new functionalities to be added to existing objects dynamically without modifying their code. It is typically used to extend the functionalities of classes in a flexible and reusable way.

image

image

Example:

// Base interface for a pizza
interface IPizza
{
    string GetDescription();
    double GetCost();
}

// Concrete implementation of a plain pizza
class PlainPizza : IPizza
{
    public string GetDescription()
    {
        return "Plain Pizza";
    }

    public double GetCost()
    {
        return 5.0;
    }
}

// Decorator base class
abstract class PizzaDecorator : IPizza
{
    protected IPizza _pizza;

    public PizzaDecorator(IPizza pizza)
    {
        _pizza = pizza;
    }

    public abstract string GetDescription();

    public abstract double GetCost();
}

// Concrete decorator for adding veg topping
class VegDecorator : PizzaDecorator
{
    public VegDecorator(IPizza pizza) : base(pizza) { }

    public override string GetDescription()
    {
        return _pizza.GetDescription() + ", Veg";
    }

    public override double GetCost()
    {
        return _pizza.GetCost() + 2.0;
    }
}

// Concrete decorator for adding chicken topping
class ChickenDecorator : PizzaDecorator
{
    public ChickenDecorator(IPizza pizza) : base(pizza) { }

    public override string GetDescription()
    {
        return _pizza.GetDescription() + ", Chicken";
    }

    public override double GetCost()
    {
        return _pizza.GetCost() + 3.0;
    }
}

class Program
{
    static void Main(string[] args)
    {
        // Create a plain pizza
        IPizza pizza = new PlainPizza();

        // Add veg toppings
        var decorator = new VegDecorator(pizza);
      
        Console.WriteLine("Description: " + decorator.GetDescription());
        Console.WriteLine("Cost: $" + decorator.GetCost());
    }
}

Facade Design Pattern

GOF Definition:

Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.

Definition:

The Facade design pattern is particularly used when a system is very complex or difficult to understand because system has a large number of interdependent subsystems/classes.

It hides the complexities of the system and provides a unified interface for the client to interact with.

image

Example:

// Subsystem 1: Order Management
class OrderManagement
{
    public void PlaceOrder(string product)
    {
        Console.WriteLine($"Placing an order for {product}...");
    }
}

// Subsystem 2: Billing
class Billing
{
    public void GenerateBill(string product)
    {
        Console.WriteLine($"Generating a bill for {product}...");
    }
}

// Subsystem 3: Payment Processing
class PaymentProcessing
{
    public void ProcessPayment(string product, decimal amount)
    {
        Console.WriteLine($"Processing payment of ${amount} for {product}...");
    }
}

// Facade (Simplify the system by hiding many subsystems)
class CustomerCareFacade
{
    private OrderManagement orderManagement;
    private Billing billing;
    private PaymentProcessing paymentProcessing;

    public CustomerCareFacade()
    {
        orderManagement = new OrderManagement();
        billing = new Billing();
        paymentProcessing = new PaymentProcessing();
    }

    public void PurchaseProduct(string product, decimal amount)
    {
        orderManagement.PlaceOrder(product);
        billing.GenerateBill(product);
        paymentProcessing.ProcessPayment(product, amount);
        Console.WriteLine("Purchase completed successfully.");
    }
}

// Client code
class Program
{
    static void Main(string[] args)
    {
        CustomerCareFacade customerCareFacade = new CustomerCareFacade();

        // Simulate a customer purchasing a product
        customerCareFacade.PurchaseProduct("Smartphone", 500.00M);
    }
}

Flyweight Design Pattern

GOF Definition:

Use sharing to support large numbers of fine-grained objects efficiently.

Definition:

The Flyweight design pattern is a structural pattern that aims to optimize memory usage by sharing common data among multiple objects. It's particularly useful when we have a large number of similar objects in our application and we want to save memory by reusing common parts of those objects instead of duplicating them.

This pattern divides an object's state into intrinsic and extrinsic parts.

Intrinsic State: This is the part of an object's state that is independent of the context in which it's used. In other words, it's the shared state that can be reused across multiple objects. Intrinsic state is typically stored in a Flyweight object.

Extrinsic State: This is the part of an object's state that depends on the context in which it's used. It's the information that varies from one object to another. Extrinsic state is passed to the Flyweight objects as parameters when they are used.

image

Example:

// Flyweight interface
interface IBird
{
    void Fly(int x, int y); // location: Extrinsic state
}

// Concrete flyweight
class ConcreteBird : IBird
{
    private string _species; // Intrinsic state

    public ConcreteBird(string species)
    {
        _species = species;
    }

    public void Fly(int x, int y)
    {
         Console.WriteLine($"A {_species} is flying to ({x}, {y})");
    }
}

// Flyweight factory
class BirdFactory
{
    private Dictionary<string, IBird> _birds = new Dictionary<string, IBird>();

    public IBird GetBird(string species)
    {
        if (!_birds.ContainsKey(species))
        {
            _birds[species] = new ConcreteBird(species);
        }
        return _birds[species];
    }
}

// Client code
class Client
{
    static void Main(string[] args)
    {
        BirdFactory birdFactory = new BirdFactory();

        // Display birds
        IBird sparrow1 = birdFactory.GetBird("Sparrow");
        sparrow1.Fly(20,30);

        IBird sparrow2 = birdFactory.GetBird("Sparrow"); // Reusing existing flyweight
        sparrow2.Fly(30,30);
    }
}

Proxy Design Pattern

GOF Definition:

Provide a surrogate or placeholder for another object to control access to it

Definition:

The Proxy Design Pattern is a structural design pattern that provides a surrogate object for another object to control access to it. It's often used to add an extra layer of control over access to an object which can be useful for various purposes like lazy loading, access control, logging, etc.

image

Example:

// The Subject interface representing the service
public interface ISubject
{
    void Request();
}

// The RealSubject class that implements the ISubject interface
public class RealSubject : ISubject
{
    public void Request()
    {
        Console.WriteLine("RealSubject: Handling request.");
    }
}

// The Proxy class that also implements the ISubject interface
public class Proxy : ISubject
{
    private RealSubject realSubject;

    public void Request()
    {
        // Check if the real subject has been created
        if (realSubject == null)
        {
            Console.WriteLine("Proxy: Creating an instance of RealSubject.");
            realSubject = new RealSubject();
        }

        // Access control or additional behavior can be implemented here

        Console.WriteLine("Proxy: Calling RealSubject's Request.");
        realSubject.Request();
    }
}

// Client code
class Program
{
    static void Main(string[] args)
    {
        // Using the Proxy to access the RealSubject
        ISubject proxy = new Proxy();
        proxy.Request();
    }
}

Chain of responsibility Design Pattern

GOF Definition:

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

Definition:

The Chain of Responsibility design pattern is a behavioral design pattern that helps in building a chain of objects to process a request. It allows to pass a request along a chain of handlers. Each handler decides either to process the request or to pass it to the next handler in the chain.

This pattern decouples the sender of the request from its receivers, giving more than one object the opportunity to handle the request.

image

Example:

// Purchase Request class
public class PurchaseRequest
{
    public string ItemName { get; }
    public double Amount { get; }

    public PurchaseRequest(string itemName, double amount)
    {
        ItemName = itemName;
        Amount = amount;
    }
}

// Approver abstract class
public abstract class Approver
{
    protected Approver NextApprover;

    public void SetNextApprover(Approver nextApprover)
    {
        NextApprover = nextApprover;
    }

    public abstract void ProcessRequest(PurchaseRequest request);
}

// Concrete Approver: Director
public class Director : Approver
{
    private double ApprovalLimit = 10000;

    public override void ProcessRequest(PurchaseRequest request)
    {
        if (request.Amount <= ApprovalLimit)
        {
            Console.WriteLine($"Director approves purchase of {request.ItemName} for ${request.Amount}");
        }
        else if (NextApprover != null)
        {
            NextApprover.ProcessRequest(request);
        }
        else
        {
            Console.WriteLine("Purchase request cannot be approved.");
        }
    }
}

// Concrete Approver: President
public class President : Approver
{
    private double ApprovalLimit = 50000;

    public override void ProcessRequest(PurchaseRequest request)
    {
        if (request.Amount <= ApprovalLimit)
        {
            Console.WriteLine($"President approves purchase of {request.ItemName} for ${request.Amount}");
        }
        else if (NextApprover != null)
        {
            NextApprover.ProcessRequest(request);
        }
        else
        {
            Console.WriteLine("Purchase request cannot be approved.");
        }
    }
}

// Client code
class Program
{
    static void Main()
    {
        // Create Approvers
        Approver director = new Director();
        Approver president = new President();

        // Set up the chain of responsibility
        director.SetNextApprover(president);

        // Create purchase requests
        PurchaseRequest request1 = new PurchaseRequest("Laptop", 8000);
        PurchaseRequest request2 = new PurchaseRequest("Conference Table", 20000);
        PurchaseRequest request3 = new PurchaseRequest("Projector", 60000);

        // Process the purchase requests
        director.ProcessRequest(request1); // Director
        director.ProcessRequest(request2); // President
        director.ProcessRequest(request3); // Can not be approved
    }
}

Command Design Pattern

GOF Definition:

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

Definition:

The Command Design Pattern is a behavioral design pattern in which a request is encapsulated as an object, known as a command, and passed to an invoker object. The invoker object is responsible for initiating the execution of the command. The invoker forwards the command to the appropriate object, known as the receiver, which can handle and execute it.

image

Example:

// Receiver: The object that performs the actual action
class Light
{
    public void TurnOn()
    {
        Console.WriteLine("Light is ON");
    }

    public void TurnOff()
    {
        Console.WriteLine("Light is OFF");
    }
}

// Command: Interface for all concrete command classes
interface ICommand
{
    void Execute();
}

// Concrete Command: Implements the ICommand interface for a specific action
class TurnOnLightCommand : ICommand
{
    private Light _light;

    public TurnOnLightCommand(Light light)
    {
        _light = light;
    }

    public void Execute()
    {
        _light.TurnOn();
    }
}

class TurnOffLightCommand : ICommand
{
    private Light _light;

    public TurnOffLightCommand(Light light)
    {
        _light = light;
    }

    public void Execute()
    {
        _light.TurnOff();
    }
}

// Invoker: Holds a reference to a command and triggers its execution
class RemoteControl
{
    private ICommand _command;

    public void SetCommand(ICommand command)
    {
        _command = command;
    }

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

// Client code
class Program
{
    static void Main(string[] args)
    {
        Light light = new Light();
        ICommand turnOnCommand = new TurnOnLightCommand(light);
        ICommand turnOffCommand = new TurnOffLightCommand(light);

        RemoteControl remote = new RemoteControl();

        remote.SetCommand(turnOnCommand);
        remote.PressButton(); // Light is ON

        remote.SetCommand(turnOffCommand);
        remote.PressButton(); // Light is OFF
    }
}

Interpreter Design Pattern

GOF Definition:

Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.

Definition:

The Interpreter Design Pattern is a behavioral design pattern that is used to define a grammar for a language and provides a way to evaluate sentences in that language.

image

Example:

// Define an abstract expression interface.
public interface IExpression
{
    int Interpret();
}

// Create a concrete expression class for a numeric value.
public class NumberExpression : IExpression
{
    private int _number;

    public NumberExpression(int number)
    {
        _number = number;
    }

    // Interpret method returns the numeric value.
    public int Interpret()
    {
        return _number;
    }
}

// Create a concrete expression class for addition.
public class AddExpression : IExpression
{
    private IExpression _left;
    private IExpression _right;

    public AddExpression(IExpression left, IExpression right)
    {
        _left = left;
        _right = right;
    }

    // Interpret method evaluates the addition operation.
    public int Interpret()
    {
        return _left.Interpret() + _right.Interpret();
    }
}

// Create a concrete expression class for subtraction.
public class SubtractExpression : IExpression
{
    private IExpression _left;
    private IExpression _right;

    public SubtractExpression(IExpression left, IExpression right)
    {
        _left = left;
        _right = right;
    }

    // Interpret method evaluates the subtraction operation.
    public int Interpret()
    {
        return _left.Interpret() - _right.Interpret();
    }
}

// Client code
class Program
{
    static void Main(string[] args)
    {
        // Create the expression tree for "2 + 3 - 1"
        IExpression expression = new SubtractExpression(
            new AddExpression(new NumberExpression(2), new NumberExpression(3)),
            new NumberExpression(1));

        // Evaluate the expression
        int result = expression.Interpret();

        Console.WriteLine("Result: " + result); // Output: Result: 4
    }
}

Iterator Design Pattern

GOF Definition:

Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

Definition:

The Iterator pattern is a behavioral design pattern that provides a way to access the elements of an aggregate object (such as a collection) sequentially without exposing its underlying representation.

This allows you to iterate over the elements of a collection without knowing how it is implemented.

image

Example:

// Define the Iterator interface
public interface IIterator
{
    bool HasNext();
    object Next();
}

// Define the Iterable interface
public interface IIterable
{
    IIterator CreateIterator();
}

// Concrete implementation of the Iterator
public class MyIterator : IIterator
{
    private readonly object[] _collection;
    private int _currentIndex = 0;

    public MyIterator(object[] collection)
    {
        _collection = collection;
    }

    public bool HasNext()
    {
        return _currentIndex < _collection.Length;
    }

    public object Next()
    {
        if (HasNext())
        {
            object currentItem = _collection[_currentIndex];
            _currentIndex++;
            return currentItem;
        }
        else
        {
            throw new InvalidOperationException("No more elements to iterate.");
        }
    }
}

// Concrete implementation of the Iterable
public class MyCollection : IIterable
{
    private readonly object[] _collection;

    public MyCollection(object[] collection)
    {
        _collection = collection;
    }

    public IIterator CreateIterator()
    {
        return new MyIterator(_collection);
    }
}

// Client code
class Program
{
    static void Main(string[] args)
    {
        object[] data = { "A", "B", "C", "D", "E" };
        IIterable collection = new MyCollection(data);
        IIterator iterator = collection.CreateIterator();

        while (iterator.HasNext())
        {
            object item = iterator.Next();
            Console.WriteLine(item);
        }
    }
}

Mediator Design Pattern

GOF Definition:

Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

Definition:

The Mediator design pattern is a behavioral pattern that promotes loose coupling between objects by encapsulating how they interact.

It centralizes communication between multiple objects through a mediator object. Instead of these objects communicating directly, they communicate through the mediator, which reduces complexity and dependencies between them.

image

image

image

Example:

// Step 1: Define the User interface
interface IUser
{
    void SendMessage(string message);
    void ReceiveMessage(string message);
}

// Step 2: Define the Mediator interface
interface IChatMediator
{
    void SendMessage(string message, IUser user);
    void AddUser(IUser user);
}

// Step 3: Implement the User
class ChatUser : IUser
{
    private string name;
    private IChatMediator mediator;

    public ChatUser(string name, IChatMediator mediator)
    {
        this.name = name;
        this.mediator = mediator;
    }

    public void SendMessage(string message)
    {
        Console.WriteLine($"{name} sends: {message}");
        mediator.SendMessage(message, this);
    }

    public void ReceiveMessage(string message)
    {
        Console.WriteLine($"{name} receives: {message}");
    }
}

// Step 4: Implement the Mediator
class ChatMediator : IChatMediator
{
    private List<IUser> users = new List<IUser>();

    public void AddUser(IUser user)
    {
        users.Add(user);
    }

    public void SendMessage(string message, IUser user)
    {
        foreach (var u in users)
        {
            if (u != user) // Don't send the message to the sender
                u.ReceiveMessage(message);
        }
    }
}

// Step 5: Client code
class Program
{
    static void Main()
    {
        IChatMediator chatMediator = new ChatMediator();

        IUser user1 = new ChatUser("Alice", chatMediator);
        IUser user2 = new ChatUser("Bob", chatMediator);
        IUser user3 = new ChatUser("Charlie", chatMediator);

        chatMediator.AddUser(user1);
        chatMediator.AddUser(user2);
        chatMediator.AddUser(user3);

        user1.SendMessage("Hello, everyone!");
        user2.SendMessage("Hi, Alice!");
    }
}

Memento Design Pattern

GOF Definition:

Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.

Definition:

The Memento design pattern is a behavioral pattern that provides a way to capture and externalize an object's internal state so that the object can be restored to that state later. This is useful in scenarios where you need to implement undo functionality, checkpoints, or history tracking.

image

image

Example:

// Originator: The object whose state needs to be saved and restored
class Originator
{
    public string State
    {
        get;
        private set;
    }

    public Memento CreateMemento()
    {
        return new Memento(State);
    }

    public void RestoreMemento(Memento memento)
    {
        State = memento.State;
        Console.WriteLine($"State restored to: {State}");
    }
}

// Memento: Stores the internal state of the Originator
class Memento
{
    public string State { get; }

    public Memento(string state)
    {
        State = state;
    }
}

// Caretaker: Manages and keeps track of multiple mementos
class Caretaker
{
    public Memento Memento
    {
        get;
        set;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        // Changing and saving states
        originator.State = "State 1";
        caretaker.Memento = originator.CreateMemento();

        originator.State = "State 2";

        // Restoring the previous state
        originator.RestoreMemento(caretaker.Memento);

        Console.ReadLine();
    }
}

Observer Design Pattern

GOF Definition:

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Definition:

The Observer Design Pattern is a behavioral pattern that defines a one-to-many dependency between objects, so that when one object (the subject) changes state, all its dependents (observers) are notified and updated automatically.

This pattern is commonly used to implement event handling systems, where multiple objects need to react to changes in another object's state.

image

Example:

// Define the Subject interface
public interface ISubject
{
    void Register(IObserver observer);
    void Unregister(IObserver observer);
    void Notify(string message);
}

// Concrete implementation of the Subject
public class ConcreteSubject : ISubject
{
    private List<IObserver> observers = new List<IObserver>();

    public void Register(IObserver observer)
    {
        observers.Add(observer);
    }

    public void Unregister(IObserver observer)
    {
        observers.Remove(observer);
    }

    public void Notify(string message)
    {
        foreach (var observer in observers)
        {
            observer.Update(message);
        }
    }
}

// The Observer interface defines the Update method that concrete observers must implement.
public interface IObserver
{
    void Update(string message);
}

// ConcreteObserver implements the IObserver interface.
// It updates itself when the subject's state changes.
public class ConcreteObserver : IObserver
{
    private string name;

    public ConcreteObserver(string name)
    {
        this.name = name;
    }

    public void Update(string message)
    {
        Console.WriteLine($"{name} received {message}");
    }
}

// Client code
class Program
{
    static void Main()
    {
        // Create a concrete subject
        var subject = new ConcreteSubject();

        // Create concrete observers
        var observer1 = new ConcreteObserver("Observer 1");
        var observer2 = new ConcreteObserver("Observer 2");

        // Register observers with the subject
        subject.Register(observer1);
        subject.Register(observer2);

        // notify observers
        subject.Notify("New State");
    }
}

State Design Pattern

GOF Definition:

Allows an object to alter its behavior when its internal state changes.

Definition:

The State Design Pattern is a behavioral design pattern that allows an object to change its behavior when its internal state changes. This pattern is particularly useful when an object has multiple states, and its behavior depends on the current state.

image

Example:

// State interface
interface ITrafficLightState
{
    void ReportState();
}

// Concrete state 1: Red Light State
class RedLightState : ITrafficLightState
{
    public void ReportState()
    {
        Console.WriteLine("Traffic light is red. Stop!");
    }
}

// Concrete state 2: Green Light State
class GreenLightState : ITrafficLightState
{
    public void ReportState()
    {
        Console.WriteLine("Traffic light is green. Go!");
    }
}

// Concrete state 3: Yellow Light State
class YellowLightState : ITrafficLightState
{
    public void ReportState()
    {
        Console.WriteLine("Traffic light is yellow. Prepare to stop.");
    }
}

// Context class
class TrafficLight
{
    private ITrafficLightState currentState;

    public TrafficLight()
    {
        // Initialize with the 'Red' state
        currentState = new RedLightState();
    }

    public void ChangeState(ITrafficLightState newState)
    {
        currentState = newState;
    }

    public void ReportState()
    {
        currentState.ReportState();
    }
}

// Client code
class Program
{
    static void Main()
    {
        TrafficLight trafficLight = new TrafficLight();

        trafficLight.ReportState(); // Initially red

        trafficLight.ChangeState(new GreenLightState());
        trafficLight.ReportState(); // Now green

        trafficLight.ChangeState(new YellowLightState());
        trafficLight.ReportState(); // Now yellow
    }
}

Strategy Design Pattern

GOF Definition:

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Definition:

The Strategy Design Pattern is a behavioral design pattern that allows you to define a family of algorithms, encapsulate each one of them, and make them interchangeable. This pattern allows a client to choose an algorithm from a family of algorithms at runtime, without altering the code that uses the algorithm.

image

Example:

// Step 1: Define the strategy interface
public interface IPaymentStrategy
{
    void ProcessPayment(double amount);
}

// Step 2: Implement concrete payment strategy classes
public class CreditCardPayment : IPaymentStrategy
{
    public void ProcessPayment(double amount)
    {
        Console.WriteLine($"Paid {amount:C} via Credit Card");
        // Implement credit card payment logic here
    }
}

public class PayPalPayment : IPaymentStrategy
{
    public void ProcessPayment(double amount)
    {
        Console.WriteLine($"Paid {amount:C} via PayPal");
        // Implement PayPal payment logic here
    }
}

// Step 3: Create a payment processor
public class PaymentProcessor
{
    private IPaymentStrategy _paymentStrategy;

    public PaymentProcessor(IPaymentStrategy paymentStrategy)
    {
        _paymentStrategy = paymentStrategy;
    }

    public void ProcessPayment(double amount)
    {
        // Delegate the payment processing to the selected strategy
        _paymentStrategy.ProcessPayment(amount);
    }
}

// Client code
class Program
{
    static void Main(string[] args)
    {
        // Step 4: Using the payment strategies
        
        // Using the payment strategies
        PaymentProcessor creditCardProcessor = new PaymentProcessor(new CreditCardPaymentStrategy());
        creditCardProcessor.ProcessPayment(100.0);

        PaymentProcessor paypalProcessor = new PaymentProcessor(new PayPalPaymentStrategy());
        paypalProcessor.ProcessPayment(50.0);
    }
}

Template Design Pattern

GOF Definition:

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

Definition:

The Template Design Pattern is a behavioral design pattern that defines the structure of an algorithm in a baseclass but lets subclasses override specific steps of the algorithm without changing its structure. It's useful when you have an algorithm with a fixed structure but with some steps that may vary depending on the specific implementation.

image

Example:

// Abstract class representing the house construction template
abstract class HouseTemplate
{
    // Template method that defines the steps for building a house
    public void BuildHouse()
    {
        BuildFoundation();
        BuildWalls();
        BuildRoof();
        DecorateHouse();
        Console.WriteLine("House construction completed.");
    }

    // Abstract methods to be implemented by concrete subclasses
    protected abstract void BuildFoundation();
    protected abstract void BuildWalls();
    protected abstract void BuildRoof();

    // Hook method (optional) that can be overridden by subclasses
    protected virtual void DecorateHouse()
    {
        Console.WriteLine("Adding basic decorations.");
    }
}

// Concrete subclass for building a wooden house
class WoodenHouse : HouseTemplate
{
    protected override void BuildFoundation()
    {
        Console.WriteLine("Building a wooden foundation.");
    }

    protected override void BuildWalls()
    {
        Console.WriteLine("Building wooden walls.");
    }

    protected override void BuildRoof()
    {
        Console.WriteLine("Building a wooden roof.");
    }

    // Override the hook method to add specific decorations for a wooden house
    protected override void DecorateHouse()
    {
        Console.WriteLine("Adding wooden decorations.");
    }
}

// Concrete subclass for building a concrete house
class ConcreteHouse : HouseTemplate
{
    protected override void BuildFoundation()
    {
        Console.WriteLine("Building a concrete foundation.");
    }

    protected override void BuildWalls()
    {
        Console.WriteLine("Building concrete walls.");
    }

    protected override void BuildRoof()
    {
        Console.WriteLine("Building a concrete roof.");
    }
}

// Client code
class Program
{
    static void Main(string[] args)
    {
        HouseTemplate woodenHouse = new WoodenHouse();
        HouseTemplate concreteHouse = new ConcreteHouse();

        Console.WriteLine("Building a wooden house:");
        woodenHouse.BuildHouse();

        Console.WriteLine("\nBuilding a concrete house:");
        concreteHouse.BuildHouse();

        Console.ReadLine();
    }
}

Visitor Design Pattern

GOF Definition:

Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates

Definition:

The Visitor Design Pattern is a behavioral design pattern that allows you to add new behaviors to a set of classes without modifying those classes. It's useful when you have a hierarchy of classes and want to perform different operations on those classes without altering their code. The Visitor pattern separates the algorithm (visitor) from the objects on which it operates (elements).

image

image

Example:

// Define the IVisitable interface, representing elements that can be visited.
interface IVisitable
{
    string Name { get; set; }
    void Accept(IVisitor visitor);
}

// Define the IVisitor interface, representing visitors that can visit IVisitable elements.
interface IVisitor
{
    void Visit(IVisitable element);
}

// Concrete implementation of IVisitor for teachers.
class Teacher : IVisitor
{
    public void Visit(IVisitable element)
    {
        Console.WriteLine($"Teacher is visiting {element.Name}");
    }
}

// Concrete implementation of IVisitable for students.
class Student : IVisitable
{
    public string Name { get; set; }

    public Student(string name)
    {
        Name = name;
    }

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

// Represents a collection of IVisitable elements.
class School : IVisitable
{
    private List<IVisitable> elements = new List<IVisitable>();

    // Attach an element to the collection.
    public void Attach(IVisitable element)
    {
        elements.Add(element);
    }

    // Detach an element from the collection.
    public void Detach(IVisitable element)
    {
        elements.Remove(element);
    }

    // Accept a visitor to visit all elements in the collection.
    public void Accept(IVisitor visitor)
    {
        foreach (var element in elements)
        {
            element.Accept(visitor);
        }
    }
}

// Client code
class Program
{
    static void Main()
    {
        // Create an object structure to hold elements.
        var school = new School();

        // Attach students to the school.
        school.Attach(new Student("Nitin"));
        school.Attach(new Student("Ed"));
        school.Attach(new Student("Marcus"));

        // Create a Teacher visitor.
        var teacher = new Teacher();

        // Allow the teacher to visit all students in the school.
        school.Accept(teacher);
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment