๐ง 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
andSmsHandler
โ 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
andDisabledState
โ 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
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.