Structural Design Patterns
Structural Design Patterns (C# / .NET)
Definition
- Focus on how classes and objects are structured
- Helps in connecting different parts of a system
Purpose
- Simplify complex structures
- Improve code organization
- Enable flexible relationships between objects
- Make systems easier to extend
Types with Real-Time Usage
1. Adapter Pattern
Idea: Converts one interface into another (compatibility layer)
Real Scenario: Integrating 3rd-party API into your system
public interface IPayment
{
void Pay();
}
// Third-party service
public class ThirdPartyPayment
{
public void MakePayment()
{
Console.WriteLine("Paid via third-party");
}
}
// Adapter
public class PaymentAdapter : IPayment
{
private readonly ThirdPartyPayment _thirdParty;
public PaymentAdapter(ThirdPartyPayment thirdParty)
{
_thirdParty = thirdParty;
}
public void Pay()
{
_thirdParty.MakePayment();
}
}
2. Decorator Pattern
Idea: Adds extra behavior without modifying original class
Real Scenario: Adding logging / validation / discount
public interface IInvoice
{
decimal GetAmount();
}
public class Invoice : IInvoice
{
public decimal GetAmount() => 1000;
}
// Decorator
public class DiscountDecorator : IInvoice
{
private readonly IInvoice _invoice;
public DiscountDecorator(IInvoice invoice)
{
_invoice = invoice;
}
public decimal GetAmount()
{
return _invoice.GetAmount() - 100;
}
}
3. Facade Pattern
Idea: Provides simple interface to complex system
Real Scenario: One method to handle order creation, payment, notification
public class OrderService
{
public void CreateOrder() => Console.WriteLine("Order Created");
}
public class PaymentService
{
public void ProcessPayment() => Console.WriteLine("Payment Done");
}
public class NotificationService
{
public void Send() => Console.WriteLine("Notification Sent");
}
// Facade
public class OrderFacade
{
private readonly OrderService _order = new();
private readonly PaymentService _payment = new();
private readonly NotificationService _notification = new();
public void PlaceOrder()
{
_order.CreateOrder();
_payment.ProcessPayment();
_notification.Send();
}
}
4. Composite Pattern
Idea: Treat individual and group objects the same
Real Scenario: Folder structure, invoice items
public interface IComponent
{
decimal GetPrice();
}
public class Product : IComponent
{
private readonly decimal _price;
public Product(decimal price)
{
_price = price;
}
public decimal GetPrice() => _price;
}
public class ProductGroup : IComponent
{
private readonly List<IComponent> _items = new();
public void Add(IComponent item)
{
_items.Add(item);
}
public decimal GetPrice()
{
return _items.Sum(x => x.GetPrice());
}
}
Pros
- ✔ Reduces complexity
- ✔ Improves flexibility
- ✔ Promotes reusable structures
- ✔ Easier maintenance
Cons
- ✖ Can increase number of classes
- ✖ Harder to understand initially
- ✖ Over-engineering for simple apps
When to Use
- When system becomes complex and tightly coupled
- When integrating external systems
- When adding features without modifying existing code
- When dealing with hierarchical (tree-like) data
Quick Mapping (Your Project)
| Feature | Pattern |
|---|---|
| 3rd-party payment API | Adapter |
| Invoice discount / tax | Decorator |
| Order processing flow | Facade |
| Invoice items (list) | Composite |
Comments
Post a Comment