Behavioral
Observer: một đơn hàng, nhiều listener
Đặt một đơn hàng và mọi dịch vụ đã đăng ký đều nghe thấy. Dịch vụ rời danh sách sẽ không nhận gì.
- Gieo
- Chăm lần cuối

Nó là gì?
Observer gồm một subject và một danh sách listener. Subject chỉ có một việc: khi có chuyện xảy ra, đi qua danh sách và báo cho từng listener. Listener tự quyết định chuyện đó nghĩa là gì.
Ở đây subject là OrderService. Sự kiện là OrderPlaced. Email, tồn kho và nhật ký kiểm toán là listener. Đơn hàng không gửi thư, không giữ hàng, không ghi log. Nó chỉ thông báo rằng đơn đã được đặt.
Khi nào dùng?
Dùng khi một sự kiện trong miền bài toán có nhiều hệ quả độc lập, và các hệ quả đó đổi thường hơn bản thân sự kiện. Thêm một email biên lai không nên buộc phải thêm một method trên đơn hàng. Đăng ký và hủy đăng ký một listener là đủ.
Đừng dùng khi phía gọi bắt buộc phải biết kết quả. Nếu đặt hàng phải thất bại vì tồn kho từ chối, đó là một lời gọi trực tiếp có giá trị trả về, không phải một thông báo. Observer không phải chỗ giấu một câu trả lời bắt buộc.
Minh họa tương tác
EmailService is now on the list. Placing an order will hand it a receipt to send.
OrderService sits on the left. EmailService, InventoryService, and AuditLog appear on the right only after you subscribe them. Publish sends OrderPlaced along the lines to the services that are still in the list.
- EmailService joins the listener list.
- InventoryService joins the same list.
- AuditLog joins. The readout shows 3 listeners.
- Place sends OrderPlaced only to services still subscribed.
0 listeners
Mã nguồn
Mã nguồn
Chỉ đọcPatterns/Behavioral/Observer/OrderService.cs
Chỉ đọc
public sealed class OrderService
{
private readonly List<IOrderListener> listeners = new();
public void Subscribe(IOrderListener listener)
{
if (!listeners.Contains(listener))
listeners.Add(listener);
}
public void Unsubscribe(IOrderListener listener)
{
listeners.Remove(listener);
}
public void Place(Order order)
{
var placed = new OrderPlaced(order.Id);
foreach (var listener in listeners)
listener.OnOrderPlaced(placed);
}
}Patterns/Behavioral/Observer/EmailService.cs
Chỉ đọc
public sealed class EmailService : IOrderListener
{
public void OnOrderPlaced(OrderPlaced placed)
{
_outbox.Enqueue(new ReceiptMail(placed.OrderId));
}
}Ưu điểm và nhược điểm
+ Ưu điểm
- OrderService không đổi khi xuất hiện listener mới.
- Mỗi listener có thể được kiểm thử với một OrderPlaced giả, không cần lớp đơn hàng.
- Hủy đăng ký chỉ là xóa khỏi danh sách, nên dịch vụ ngừng hoạt động sẽ hết nhận sự kiện.
− Nhược điểm
- Thứ tự listener dễ trở thành hợp đồng ngầm nếu listener này phụ thuộc listener kia.
- Một listener ném lỗi có thể chặn phần còn lại của danh sách nếu bạn không cô lập lời gọi.
- Lỗi dễ bị bỏ sót, vì subject không chờ kết quả.
Mẹo
- 01Đặt tên sự kiện theo việc đã xảy ra, như OrderPlaced, không đặt theo việc listener sẽ làm.
- 02Bọc từng listener trong try riêng nếu lỗi của một listener không được hủy các listener còn lại.
- 03Đừng để listener gọi lại Place. Lời gọi đó đi vào danh sách mà bạn đang duyệt.
Tiếp theo
Bài kế trong đường đọc: Thiết Kế RAG Pipeline: Chunking, Retrieval, Reranking, và Generation