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

Popular posts from this blog

Promises in Angular

Debouncing & Throttling in RxJS: Optimizing API Calls and User Interactions

Comprehensive Guide to C# and .NET Core OOP Concepts and Language Features