C# Design Patterns: Essential Reference for Developers
C# Design Patterns: Essential Reference
Creational Design Patterns
| Pattern | When to Use | Key Implementation |
|---|---|---|
| Singleton | Need exactly one instance globally accessible. | private static Singleton _instance;public static Singleton Instance => _instance ??= new Singleton(); |
| Factory | Create objects without specifying concrete classes. | public static IProduct Create(string type) => type switch { "A" => new ProductA(), ... } |
| Builder | Construct complex objects step-by-step. | public class CarBuilder { ... public CarBuilder WithEngine(...) { ... } } |
| Prototype | Clone existing objects instead of creating new ones. | public interface IPrototype { IPrototype Clone(); } |
Structural Design Patterns
| Pattern | When to Use | Key Implementation |
|---|---|---|
| Adapter | Make incompatible interfaces work together. | public class NewSystemAdapter : ILegacyInterface { private NewSystem _newSystem; } |
| Decorator | Add functionality to objects dynamically. | public abstract class CoffeeDecorator : ICoffee { protected ICoffee _decoratedCoffee; } |
| Facade | Simplify complex systems with a unified interface. | public class OrderFacade { public void PlaceOrder() { /* calls 5+ subsystems */ } } |
| Proxy | Control access to another object. | public class Proxy : IService { private RealService _service; public void Request() { /* access control */ } } |
Behavioral Design Patterns
| Pattern | When to Use | Key Implementation |
|---|---|---|
| Observer | Notify multiple objects about state changes. | public class Subject { private List<IObserver> _observers = new(); public void Notify() { ... } } |
| Strategy | Switch algorithms at runtime. | public class Context { private IStrategy _strategy; public void SetStrategy(IStrategy s) { ... } } |
| Command | Encapsulate requests as objects. | public interface ICommand { void Execute(); }public class OrderCommand : ICommand { ... } |
| State | Change object behavior when its state changes. | public class Context { private IState _state; public void Request() { _state.Handle(); } } |
Key Software Design Principles
Encapsulate What Varies
Separate changing parts from stable parts.Program to Interfaces, Not Implementations
List<IShape> shapes = new();notList<Circle> circles = new();Favor Composition Over Inheritance
Car _engine = new V8Engine();vsclass Car : EngineSOLID 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)
English with a size of 12.41 KB