๐Ÿง  Mastering 5 Design Patterns in C# - Part 3

โœจ Introduction

Continuing our deep dive into design patterns, we now arrive at the final part of the series. In this concluding section, weโ€™ll explore 5 additional patterns that bring advanced flexibility and control to software architecture. Still using the same notification system context, weโ€™ll examine

  • Chain of Responsibility

  • Mediator

  • State

  • Builder

  • Memento


๐Ÿ”— 1. Chain of Responsibility โ€“ Sequential Processing

โœ… Intent

Pass a request along a chain of handlers until one handles it.

๐ŸŽฏ Purpose

Use when you need to process requests through a sequence of steps, where each handler decides whether to act or pass it along.

๐Ÿงฉ Code

public abstract class NotificationHandler
{
    protected NotificationHandler _next;

    public void SetNext(NotificationHandler next) => _next = next;

    public abstract void Handle(string message);
}

public class EmailHandler : NotificationHandler
{
    public override void Handle(string message)
    {
        if (message.Contains("email"))
            Console.WriteLine($"Handled by Email: {message}");
        else
            _next?.Handle(message);
    }
}

public class SmsHandler : NotificationHandler
{
    public override void Handle(string message)
    {
        if (message.Contains("sms"))
            Console.WriteLine($"Handled by SMS: {message}");
        else
            _next?.Handle(message);
    }
}

๐Ÿง  Explanation

  • NotificationHandler โ†’ Base handler with chaining logic.

  • EmailHandler and SmsHandler โ†’ Handle specific message types.

๐Ÿ‘ Pros

  • Flexible and extensible.

  • Decouples sender from receiver.

๐Ÿ‘Ž Cons

  • Hard to trace flow.

  • Handlers must be carefully ordered.


๐Ÿงญ 2. Mediator โ€“ Centralized Communication

โœ… Intent

Define an object that encapsulates how a set of objects interact.

๐ŸŽฏ Purpose

Use when you want to reduce direct dependencies between objects, centralizing communication logic.

๐Ÿงฉ Code

public interface IMediator
{
    void Notify(object sender, string message);
}

public class NotificationMediator : IMediator
{
    public void Notify(object sender, string message)
    {
        Console.WriteLine($"Mediator received: {message}");
    }
}

public class EmailComponent
{
    private readonly IMediator _mediator;

    public EmailComponent(IMediator mediator)
    {
        _mediator = mediator;
    }

    public void Send(string message)
    {
        _mediator.Notify(this, $"Email: {message}");
    }
}

๐Ÿง  Explanation

  • IMediator โ†’ Interface for communication.

  • NotificationMediator โ†’ Central hub.

  • EmailComponent โ†’ Sends via mediator.

๐Ÿ‘ Pros

  • Reduces coupling.

  • Centralizes logic.

๐Ÿ‘Ž Cons

  • Mediator can become complex.

  • Harder to debug interactions.


๐ŸŽญ 3. State โ€“ Dynamic Behavior

โœ… Intent

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

๐ŸŽฏ Purpose

Use when an objectโ€™s behavior depends on its state, and you want to avoid complex conditionals.

๐Ÿงฉ Code

public interface INotificationState
{
    void Send(string message);
}

public class ActiveState : INotificationState
{
    public void Send(string message)
    {
        Console.WriteLine($"Active: {message}");
    }
}

public class DisabledState : INotificationState
{
    public void Send(string message)
    {
        Console.WriteLine("Notifications are disabled.");
    }
}

public class NotificationContext
{
    private INotificationState _state;

    public NotificationContext(INotificationState state)
    {
        _state = state;
    }

    public void SetState(INotificationState state) => _state = state;

    public void Send(string message) => _state.Send(message);
}

๐Ÿง  Explanation

  • INotificationState โ†’ Interface for states.

  • ActiveState and DisabledState โ†’ Define behavior.

  • NotificationContext โ†’ Switches states dynamically.

๐Ÿ‘ Pros

  • Cleaner state management.

  • Avoids conditionals.

๐Ÿ‘Ž Cons

  • Requires multiple classes.

  • Can be overkill for simple logic.


๐Ÿงฑ 4. Builder โ€“ Step-by-Step Construction

โœ… Intent

Separate the construction of a complex object from its representation.

๐ŸŽฏ Purpose

Use when you need to build complex objects step by step, especially when there are many optional parts.

๐Ÿงฉ Code

public class Notification
{
    public string Title { get; set; }
    public string Body { get; set; }
    public bool SendEmail { get; set; }
    public bool SendSms { get; set; }

    public void Show()
    {
        Console.WriteLine($"Title: {Title}, Body: {Body}, Email: {SendEmail}, SMS: {SendSms}");
    }
}

public class NotificationBuilder
{
    private readonly Notification _notification = new();

    public NotificationBuilder SetTitle(string title)
    {
        _notification.Title = title;
        return this;
    }

    public NotificationBuilder SetBody(string body)
    {
        _notification.Body = body;
        return this;
    }

    public NotificationBuilder EnableEmail()
    {
        _notification.SendEmail = true;
        return this;
    }

    public NotificationBuilder EnableSms()
    {
        _notification.SendSms = true;
        return this;
    }

    public Notification Build() => _notification;
}

๐Ÿง  Explanation

  • Notification โ†’ Final object.

  • NotificationBuilder โ†’ Builds it step by step.

๐Ÿ‘ Pros

  • Clear and readable construction.

  • Flexible for optional parameters.

๐Ÿ‘Ž Cons

  • Requires extra class.

  • Can be verbose for simple objects.


๐Ÿง  5. Memento โ€“ State Snapshot

โœ… Intent

Capture and restore an objectโ€™s internal state without violating encapsulation.

๐ŸŽฏ Purpose

Use when you need to implement undo/redo functionality or preserve historical states.

๐Ÿงฉ Code

public class NotificationMemento
{
    public string Message { get; }

    public NotificationMemento(string message)
    {
        Message = message;
    }
}

public class NotificationOriginator
{
    private string _message;

    public void SetMessage(string message)
    {
        _message = message;
        Console.WriteLine($"Current message: {_message}");
    }

    public NotificationMemento Save() => new(_message);

    public void Restore(NotificationMemento memento)
    {
        _message = memento.Message;
        Console.WriteLine($"Restored message: {_message}");
    }
}

๐Ÿง  Explanation

  • NotificationMemento โ†’ Stores state.

  • NotificationOriginator โ†’ Saves and restores state.

๐Ÿ‘ Pros

  • Enables undo/redo.

  • Preserves encapsulation.

๐Ÿ‘Ž Cons

  • Can consume memory.

  • Requires careful state management.


๐Ÿงพ Conclusion

These final five design patterns offer powerful tools for managing complexity and behavior:

  • Chain of Responsibility handles requests in sequence.

  • Mediator centralizes communication.

  • State enables dynamic behavior.

  • Builder simplifies object construction.

  • Memento preserves and restores state.

Together with the previous ten patterns, you now have a solid foundation for building scalable, maintainable C# applications.

#CSharp #DesignPatterns #DotNet #SoftwareDesign #CodeArchitecture #BackendEngineering #CleanCode #DevTips #ChainOfResponsability #Mediator #State #Builder #Memento #Development #Developer

0
Subscribe to my newsletter

Read articles from Johnny Hideki Kinoshita de Faria directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Johnny Hideki Kinoshita de Faria
Johnny Hideki Kinoshita de Faria

Technology professional with over 15 years of experience delivering innovative, scalable, and secure solutions โ€” especially within the financial sector. I bring deep expertise in Oracle PL/SQL (9+ years), designing robust data architectures that ensure performance and reliability. On the back-end side, Iโ€™ve spent 6 years building enterprise-grade applications using .NET, applying best practices like TDD and clean code to deliver high-quality solutions. In addition to my backend strengths, I have 6 years of experience with PHP and JavaScript, allowing me to develop full-stack web applications that combine strong performance with intuitive user interfaces. I've led and contributed to projects involving digital account management, integration of VISA credit and debit transactions, modernization of payment systems, financial analysis tools, and fraud prevention strategies. Academically, I hold a postgraduate certificate in .NET Architecture and an MBA in IT Project Management, blending technical skill with business acumen. Over the past 6 years, Iโ€™ve also taken on leadership roles โ€” managing teams, mentoring developers, and driving strategic initiatives. I'm fluent in agile methodologies and make consistent use of tools like Azure Boards to coordinate tasks and align team performance with delivery goals.