C# Design Patterns (Intermediate): Practical Patterns, Use Cases, and Alternatives

C# Design Patterns (Intermediate): Practical Patterns, Use Cases, and Alternatives

At the intermediate level, design patterns focus more on flexibility, extensibility, and separation of concerns. These patterns are widely used in real-world applications and often appear in frameworks and enterprise systems.

Selected Intermediate Design Patterns

We’ll cover the following:

• Strategy Pattern
• Repository Pattern
• Decorator Pattern
• Command Pattern

1. Strategy Pattern

Purpose: Defines a family of algorithms and allows them to be interchangeable at runtime.

When to Use

• Multiple ways to perform a task
• Avoiding large conditional statements

Example

public interface IPaymentStrategy
{
    void Pay(decimal amount);
}

public class CreditCardPayment : IPaymentStrategy
{
    public void Pay(decimal amount)
    {
        Console.WriteLine($"Paid {amount} using Credit Card");
    }
}

public class PayPalPayment : IPaymentStrategy
{
    public void Pay(decimal amount)
    {
        Console.WriteLine($"Paid {amount} using PayPal");
    }
}

public class PaymentContext
{
    private IPaymentStrategy _strategy;

    public void SetStrategy(IPaymentStrategy strategy)
    {
        _strategy = strategy;
    }

    public void ExecutePayment(decimal amount)
    {
        _strategy.Pay(amount);
    }
}

Usage

var context = new PaymentContext();

context.SetStrategy(new CreditCardPayment());
context.ExecutePayment(100);

context.SetStrategy(new PayPalPayment());
context.ExecutePayment(200);

Advantages of Strategy Pattern

• Eliminates conditional logic
• Promotes Open/Closed Principle
• Easy to extend with new strategies

Alternatives of Strategy Pattern

• Simple switch-case (less flexible)
• Delegates or Func (lighter-weight approach in C#)

2. Repository Pattern

Purpose: Abstracts data access logic and provides a clean separation between business logic and data layer.

When to Use

• Applications with database interaction
• Implementing clean architecture

Example

public interface IRepository
{
    IEnumerable GetAll();
    T GetById(int id);
    void Add(T entity);
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class ProductRepository : IRepository
{
    private readonly List _products = new List();

    public IEnumerable GetAll() => _products;

    public Product GetById(int id) =>
        _products.FirstOrDefault(p => p.Id == id);

    public void Add(Product entity)
    {
        _products.Add(entity);
    }
}

Usage

var repo = new ProductRepository();

repo.Add(new Product { Id = 1, Name = "Laptop" });

var product = repo.GetById(1);
Console.WriteLine(product.Name);

Advantages of Repository Pattern

• Decouples business logic from data access
• Easier to test (mock repositories)
• Centralized data logic

Alternatives of Repository Pattern

• Direct use of ORM (like Entity Framework DbContext)
• CQRS for more complex systems

3. Decorator Pattern

Purpose: Adds behavior to objects dynamically without modifying their structure.

When to Use

• Extending functionality without inheritance
• Adding responsibilities at runtime

Example

public interface IMessage
{
    string GetContent();
}

public class SimpleMessage : IMessage
{
    public string GetContent() => "Hello";
}

public abstract class MessageDecorator : IMessage
{
    protected IMessage _message;

    public MessageDecorator(IMessage message)
    {
        _message = message;
    }

    public abstract string GetContent();
}

public class ExclamationDecorator : MessageDecorator
{
    public ExclamationDecorator(IMessage message) : base(message) { }

    public override string GetContent()
    {
        return _message.GetContent() + "!";
    }
}

Usage

IMessage message = new SimpleMessage();
message = new ExclamationDecorator(message);

Console.WriteLine(message.GetContent()); // Hello!

Advantages of Decorator Pattern

• Flexible alternative to inheritance
• Follows Open/Closed Principle
• Combine multiple behaviors

Alternatives of Decorator Pattern

• Inheritance (less flexible)
• Extension methods (limited use cases)

4. Command Pattern

Purpose: Encapsulates a request as an object, allowing you to parameterize and queue operations.

When to Use

• Undo/redo functionality
• Task scheduling
• Decoupling sender and receiver

Example

public interface ICommand
{
    void Execute();
}

public class Light
{
    public void TurnOn() => Console.WriteLine("Light is ON");
}

public class TurnOnCommand : ICommand
{
    private readonly Light _light;

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

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

public class RemoteControl
{
    private ICommand _command;

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

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

Usage

var light = new Light();
var command = new TurnOnCommand(light);

var remote = new RemoteControl();
remote.SetCommand(command);
remote.PressButton();

Advantages of Command Pattern

• Decouples invoker from receiver
• Supports undo/redo
• Enables command queuing

Alternatives of Command Pattern

• Direct method calls (simpler but tightly coupled)
• Delegates/Action (lighter approach in C#)

Summary Table

Pattern Purpose Best Use Case Alternative
Strategy Interchangeable algorithms Payment systems, sorting Switch-case, delegates
Repository Data access abstraction Database-driven apps ORM direct usage
Decorator Dynamic behavior extension UI, logging, streams Inheritance
Command Encapsulate requests Undo/redo, task queues Direct calls, delegates

Closing Thoughts

Intermediate design patterns help you move beyond basic structure into real-world architecture decisions. Mastering these patterns allows you to build systems that are easier to scale, test, and maintain.

Contents related to 'C# Design Patterns (Intermediate): Practical Patterns, Use Cases, and Alternatives'

C# Design Patterns for Beginners: Concepts, Benefits, and Practical Examples
C# Design Patterns for Beginners: Concepts, Benefits, and Practical Examples
Advanced C# Design Patterns: Scalable Architecture, Complex Patterns, and Real-World Applications
Advanced C# Design Patterns: Scalable Architecture, Complex Patterns, and Real-World Applications