Chuyển tới nội dung chính

Structural Design Patterns

Structural Pattern là gì? (What Are Structural Patterns?)

Structural patterns xử lý cách các class và object được tổ chức (Compose) thành cấu trúc lớn hơn. Chúng tập trung vào mối quan hệ giữa các thực thể — giúp thay đổi hoặc mở rộng chức năng mà không cần viết lại mọi thứ. Hãy nghĩ về chúng như chất keo (Glue) kết nối kiến trúc của bạn.

Nếu Creational Pattern trả lời "làm sao tạo object?", thì Structural Pattern trả lời "làm sao kết nối chúng với nhau?"

Tại sao quan trọng (Why They Matter)

Vấn đềPattern giải quyết
Interface không tương thích cần hoạt động cùng nhauAdapter
Muốn tách abstraction khỏi implementation để cả hai thay đổi độc lậpBridge
Cần xử lý object đơn lẻ và nhóm object theo cùng một cáchComposite
Muốn thêm trách nhiệm (Responsibility) cho object động, không cần subclassDecorator
Cần interface đơn giản cho một subsystem phức tạpFacade
Cần chia sẻ state chung cho nhiều object tương tự để tiết kiệm bộ nhớFlyweight
Cần placeholder để kiểm soát truy cập đến object khácProxy

Miền Coffee Shop (The Coffee Shop Domain)

Tất cả ví dụ trong phần này tiếp tục sử dụng miền Coffee Shop từ Creational Pattern. Chúng ta xây dựng dựa trên model cốt lõi:

// Base product — kế thừa từ Creational Pattern
public abstract class Coffee
{
public string Name { get; init; } = "";
public double Price { get; init; }
public List<string> Ingredients { get; init; } = new();
public CupSize Size { get; init; } = CupSize.Medium;

public override string ToString() =>
$"{Name} ({Size}) — ${Price:F2} [{string.Join(", ", Ingredients)}]";
}

public enum CupSize { Small, Medium, Large }

So sánh các Pattern (Pattern Comparison)

PatternMục đích (Intent)Khi nào sử dụng
AdapterChuyển đổi interface này thành interface khácTích hợp third-party, wrapper legacy code
BridgeTách abstraction khỏi implementationBiến thể đa chiều (nền tảng × định dạng)
CompositeCấu trúc cây (Tree Structure) của objectMenu, file system, sơ đồ tổ chức
DecoratorThêm hành vi động (Dynamic Behavior)Topping, middleware, streaming wrapper
FacadeInterface đơn giản cho subsystem phức tạpAPI phức tạp, orchestration service
FlyweightChia sẻ object tinh granularity hiệu quảSố lượng lớn object tương tự (game object, ký tự văn bản)
ProxyKiểm soát truy cập đến object khácLazy loading, access control, caching, logging

Lỗi thường gặp (Common Pitfalls)

  • Lạm dụng Adapter: Đừng tạo adapter cho mọi class. Chỉ dùng khi thực sự cần kết nối interface không tương thích.
  • Decorator explosion: Quá nhiều decorator khiến debug khó — call stack bị lồng sâu. Giữ chuỗi ngắn và có ý nghĩa.
  • Facade trở thành god object: Facade đơn giản hóa truy cập, không sở hữu logic. Nó nên ủy quyền (Delegate), không chứa business logic.
  • Tối ưu hóa Flyweight prematurely: Chỉ dùng Flyweight khi đã đo lường được vấn đề bộ nhớ. Đừng tối ưu theo dự đoán.