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

โœจ Introduction

Continuing our deep dive into design patterns, this third part explores 5 additional patterns that enhance scalability, modularity, and dependency control. Still using the notification system as our context, weโ€™ll cover:

  • Flyweight

  • Prototype

  • Visitor

  • Interpreter

  • Service Locator


๐Ÿชถ 1. Flyweight โ€“ Memory Optimization

โœ… Intent

Minimize memory usage by sharing common data between similar objects.

๐ŸŽฏ Purpose

Useful when your system creates many similar objects, like notifications with repeated styles.

๐Ÿงฉ Code

public class NotificationStyle
{
    public string Font { get; set; }
    public string Color { get; set; }
}

public class StyleFactory
{
    private readonly Dictionary<string, NotificationStyle> _styles = new();

    public NotificationStyle GetStyle(string key)
    {
        if (!_styles.ContainsKey(key))
        {
            _styles[key] = new NotificationStyle { Font = "Arial", Color = key };
        }
        return _styles[key];
    }
}

๐Ÿง  Explanation

  • StyleFactory shares style instances to save memory.

๐Ÿ‘ Pros

  • Reduces memory footprint.

  • Improves performance.

๐Ÿ‘Ž Cons

  • Adds complexity.

  • Harder with mutable objects.


๐Ÿงฌ 2. Prototype โ€“ Object Cloning

โœ… Intent

Create new objects by copying an existing instance.

๐ŸŽฏ Purpose

Ideal when object creation is expensive or complex, and you want to duplicate with slight variations.

๐Ÿงฉ Code

public class Notification : ICloneable
{
    public string Title { get; set; }
    public string Message { get; set; }

    public object Clone()
    {
        return MemberwiseClone();
    }
}

๐Ÿง  Explanation

  • ICloneable allows quick duplication of notifications.

๐Ÿ‘ Pros

  • Fast object creation.

  • Avoids repetitive setup.

๐Ÿ‘Ž Cons

  • May result in shallow copies.

  • Tricky with deep object graphs.


๐Ÿงญ 3. Visitor โ€“ External Operations

โœ… Intent

Add operations to objects without modifying their classes.

๐ŸŽฏ Purpose

Great for performing multiple actions on a structure of objects, like exporting notifications.

๐Ÿงฉ Code

public interface IVisitable
{
    void Accept(INotificationVisitor visitor);
}

public interface INotificationVisitor
{
    void Visit(Notification notification);
}

public class Notification : IVisitable
{
    public string Message { get; set; }

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

public class ExportVisitor : INotificationVisitor
{
    public void Visit(Notification notification)
    {
        Console.WriteLine($"Exporting: {notification.Message}");
    }
}

๐Ÿง  Explanation

  • Visitor separates export logic from the core class.

๐Ÿ‘ Pros

  • Highly extensible.

  • Keeps classes clean.

๐Ÿ‘Ž Cons

  • Adds complexity.

  • Harder with deep hierarchies.


๐Ÿงฎ 4. Interpreter โ€“ Custom Language

โœ… Intent

Interpret sentences in a custom language.

๐ŸŽฏ Purpose

Useful for custom notification commands, like filters or rules.

๐Ÿงฉ Code

public interface IExpression
{
    bool Interpret(string context);
}

public class ContainsExpression : IExpression
{
    private readonly string _keyword;

    public ContainsExpression(string keyword)
    {
        _keyword = keyword;
    }

    public bool Interpret(string context)
    {
        return context.Contains(_keyword);
    }
}

๐Ÿง  Explanation

  • ContainsExpression checks if a message contains a keyword.

๐Ÿ‘ Pros

  • Flexible for rule engines.

  • Easy to extend.

๐Ÿ‘Ž Cons

  • Can be slow.

  • Hard to scale for complex grammars.


๐Ÿงญ 5. Service Locator โ€“ Centralized Access

โœ… Intent

Provide a way to locate services without direct dependencies.

๐ŸŽฏ Purpose

Ideal for managing dependencies like notification channels.

๐Ÿงฉ Code

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

public class EmailService : INotificationService
{
    public void Send(string message) => Console.WriteLine($"Email: {message}");
}

public class ServiceLocator
{
    private static readonly Dictionary<string, INotificationService> _services = new();

    public static void Register(string key, INotificationService service)
    {
        _services[key] = service;
    }

    public static INotificationService GetService(string key)
    {
        return _services[key];
    }
}

๐Ÿง  Explanation

  • ServiceLocator centralizes access to notification services.

๐Ÿ‘ Pros

  • Reduces coupling.

  • Easy to swap implementations.

๐Ÿ‘Ž Cons

  • Can obscure dependencies.

  • Less transparent than dependency injection.


๐Ÿงพ Conclusion

These five patterns expand your toolkit for building scalable, maintainable systems:

  • Flyweight saves memory.

  • Prototype enables cloning.

  • Visitor separates operations.

  • Interpreter supports custom rules.

  • Service Locator centralizes dependencies.

#CSharp #DesignPatterns #DotNet #SoftwareEngineering #CleanArchitecture #BackendDev #CodeQuality #ProgrammingTips #Flyweight #Protoype #Visitor #Interpreter #ServiceLocator

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.