C# Design Patterns: Essential Reference for Developers

Posted by Anonymous and classified in Computers

Written on in English with a size of 12.41 KB

C# Design Patterns: Essential Reference

Creational Design Patterns

PatternWhen to UseKey Implementation
SingletonNeed exactly one instance globally accessible.private static Singleton _instance;
public static Singleton Instance => _instance ??= new Singleton();
FactoryCreate objects without specifying concrete classes.public static IProduct Create(string type) => type switch { "A" => new ProductA(), ... }
BuilderConstruct complex objects step-by-step.public class CarBuilder { ... public CarBuilder WithEngine(...) { ... } }
PrototypeClone existing objects instead of creating new ones.public interface IPrototype { IPrototype Clone(); }

Structural Design Patterns

PatternWhen to UseKey Implementation
AdapterMake incompatible interfaces work together.public class NewSystemAdapter : ILegacyInterface { private NewSystem _newSystem; }
DecoratorAdd functionality to objects dynamically.public abstract class CoffeeDecorator : ICoffee { protected ICoffee _decoratedCoffee; }
FacadeSimplify complex systems with a unified interface.public class OrderFacade { public void PlaceOrder() { /* calls 5+ subsystems */ } }
ProxyControl access to another object.public class Proxy : IService { private RealService _service; public void Request() { /* access control */ } }

Behavioral Design Patterns

PatternWhen to UseKey Implementation
ObserverNotify multiple objects about state changes.public class Subject { private List<IObserver> _observers = new(); public void Notify() { ... } }
StrategySwitch algorithms at runtime.public class Context { private IStrategy _strategy; public void SetStrategy(IStrategy s) { ... } }
CommandEncapsulate requests as objects.public interface ICommand { void Execute(); }
public class OrderCommand : ICommand { ... }
StateChange object behavior when its state changes.public class Context { private IState _state; public void Request() { _state.Handle(); } }

Key Software Design Principles

  1. Encapsulate What Varies
    Separate changing parts from stable parts.

  2. Program to Interfaces, Not Implementations
    List<IShape> shapes = new(); not List<Circle> circles = new();

  3. Favor Composition Over Inheritance
    Car _engine = new V8Engine(); vs class Car : Engine

  4. SOLID Principles:

    • Single Responsibility Principle

    • Open/Closed Principle

    • Liskov Substitution Principle

    • Interface Segregation Principle

    • Dependency Inversion Principle

Common Anti-Patterns to Avoid

  • God Object: A single class handling too many responsibilities.

  • Spaghetti Code: Lack of clear structure, with tangled dependencies.

  • Reinvent the Wheel: Developing custom solutions for already solved problems.

  • Pattern Overuse: Applying complex patterns when simpler code is sufficient.


Top 5 Essential C# Design Patterns

1. Singleton Pattern (Global Access)

public class Logger {
    private static Logger _instance;
    private static readonly object _lock = new();
    private Logger() {}
    public static Logger Instance {
        get {
            lock (_lock) {
                return _instance ??= new Logger();
            }
        }
    }
}

2. Factory Pattern (Creation Delegation)

public interface IAnimal { void Speak(); }
public class Dog : IAnimal { public void Speak() => Console.WriteLine("Woof!"); }

public static class AnimalFactory {
    public static IAnimal Create(string type) => type switch {
        "dog" => new Dog(),
        "cat" => new Cat(),
        _ => throw new ArgumentException("Invalid animal type")
    };
}

3. Observer Pattern (Event Notification)

public class NewsPublisher {
    private List<ISubscriber> _subscribers = new();
    public void Subscribe(ISubscriber s) => _subscribers.Add(s);
    public void Notify(string news) => _subscribers.ForEach(s => s.Update(news));
}

public class Subscriber : ISubscriber {
    public void Update(string news) => Console.WriteLine($"Received: {news}");
}

4. Strategy Pattern (Algorithm Switching)

public interface IPaymentStrategy {
    void Pay(double amount);
}
public class CreditCardPayment : IPaymentStrategy {
    public void Pay(double amount) => Console.WriteLine($"Paid ${amount} via Credit Card");
}

public class ShoppingCart {
    private IPaymentStrategy _payment;
    public void SetPayment(IPaymentStrategy payment) => _payment = payment;
    public void Checkout(double total) => _payment.Pay(total);
}

5. Decorator Pattern (Dynamic Extensions)

public interface ICoffee { double Cost(); }
public class BasicCoffee : ICoffee { public double Cost() => 2.50; }

public class MilkDecorator : ICoffee {
    private readonly ICoffee _coffee;
    public MilkDecorator(ICoffee coffee) => _coffee = coffee;
    public double Cost() => _coffee.Cost() + 0.50;
}

<em>// Usage:</em>
ICoffee coffee = new MilkDecorator(new BasicCoffee());
Console.WriteLine(coffee.Cost()); <em>// Output: 3.00</em>

Important Reminders:
🛠️ Patterns are tools, not goals.
🔧 Use them when they solve specific problems.
⚖️ Simplicity > Pattern Correctness.
📚 Reference: <em>Design Patterns: Elements of Reusable Object-Oriented Software</em> (Gang of Four)

Related entries: