Observer Pattern là một mẫu thiết kế thuộc nhóm Behavioral Pattern. Nó cho phép đối tượng thông báo cho các thành phần phụ thuộc của nó một cách tự động khi có sự thay đổi trạng thái. Cùng nhau tìm hiểu chi tiết về mẫu thiết kế này.
Giới thiệu
Mẫu Observer giúp xây dựng mối quan hệ một-nhiều giữa các đối tượng. Khi một đối tượng có sự thay đổi trạng thái, tất cả các thành phần phụ thuộc của nó sẽ được thông báo và cập nhật tự động. Ví dụ, khi bạn đăng ký thông báo từ một kênh YouTube, bạn sẽ nhận thông báo (tự động) mỗi khi kênh đó có video mới.
Kiến trúc
Các thành phần chính trong mô hình này bao gồm:
- Publisher (subject): là đối tượng cần lắng nghe sự kiện. Khi có sự kiện xảy ra, publisher sẽ thông báo cho Subscriber (observer).
- Subscriber: là một interface mà Publisher sử dụng để báo cáo mỗi khi có sự kiện xảy ra. Thường chỉ gồm một phương thức cập nhật duy nhất.
- ConcreteSubscriber: là lớp cụ thể thực hiện các hành động khi nhận được thông báo từ Publisher.
Ưu & nhược điểm
Ưu điểm
- Đảm bảo nguyên tắc Open/Closed Principle (OCP): Cho phép thay đổi Subject và Observer một cách độc lập. Chúng ta có thể tái sử dụng các Subject mà không cần tái sử dụng các Observer và ngược lại.
- Thiết lập mối quan hệ giữa các objects trong thời gian chạy.
- Sự thay đổi trạng thái ở 1 đối tượng có thể được thông báo đến các đối tượng khác mà không phải giữ chúng liên kết quá chặt chẽ.
- Không giới hạn số lượng Observer.
Nhược điểm
- Unexpected update: Vì các Observer không biết về sự hiện diện của nhau, nó có thể tốn nhiều chi phí khi thay đổi Subject.
- Subscriber được thông báo theo thứ tự ngẫu nhiên.
Khi nào thì sử dụng
Sử dụng Observer Pattern khi chúng ta muốn:
- Sự thay đổi trạng thái ở 1 đối tượng cần được thông báo đến các đối tượng khác mà không phải giữ chúng liên kết quá chặt chẽ.
- Cần mở rộng dự án với ít sự thay đổi nhất.
- Khi abstraction có 2 khía cạnh, cái này phụ thuộc cái kia. Đóng gói các khía cạnh này trong các đối tượng khác nhau cho phép bạn thay đổi và tái sử dụng chúng độc lập.
- Khi thay đổi một đối tượng yêu cầu việc thay đổi đến các đối tượng khác, và bạn không biết số lượng đối tượng cần thay đổi.
- Khi một đối tượng thông báo các đối tượng khác mà không cần biết đối tượng đó là gì hay tránh tightly coupled.
Source code minh họa với C
Để minh họa thêm về Observer Pattern, hãy xem qua một đoạn mã C# đơn giản:
public interface IObserver
{
void Update(ISubject subject);
}
public interface ISubject
{
void Attach(IObserver observer);
void Detach(IObserver observer);
void Notify();
}
public class Subject : ISubject
{
private List _observers = new List();
public void Attach(IObserver observer)
{
Console.WriteLine("Subject: Attached an observer.");
this._observers.Add(observer);
}
public void Detach(IObserver observer)
{
this._observers.Remove(observer);
Console.WriteLine("Subject: Detached an observer.");
}
public void Notify()
{
Console.WriteLine("Subject: Notifying observers...");
foreach (var observer in _observers)
{
observer.Update(this);
}
}
public void SomeBusinessLogic()
{
Console.WriteLine("Subject: I'm doing something important.");
this.Notify();
}
}
public class ConcreteObserverA : IObserver
{
public void Update(ISubject subject)
{
if ((subject as Subject).State 3)
{
Console.WriteLine("ConcreteObserverA: Reacted to the event.");
}
}
}
public class ConcreteObserverB : IObserver
{
public void Update(ISubject subject)
{
if ((subject as Subject).State == 0 || (subject as Subject).State >= 2)
{
Console.WriteLine("ConcreteObserverB: Reacted to the event.");
}
}
}
class Program
{
static void Main(string[] args)
{
var subject = new Subject();
var observerA = new ConcreteObserverA();
subject.Attach(observerA);
var observerB = new ConcreteObserverB();
subject.Attach(observerB);
subject.SomeBusinessLogic();
subject.Detach(observerB);
subject.SomeBusinessLogic();
}
}
Design Pattern liên quan
- Chain of Responsibility, Command, Mediator và Observer là các cách giải quyết khác nhau cho bài toán kết nối người gửi và người nhận yêu cầu.
- Chain of Responsibility chuyển một yêu cầu tuần tự dọc theo một chuỗi động gồm những người nhận tiềm năng cho đến khi một trong số chúng xử lý yêu cầu đó.
- Command thiết lập kết nối một chiều giữa người gửi và người nhận.
- Mediator loại bỏ các kết nối trực tiếp giữa người gửi và người nhận, buộc họ phải giao tiếp gián tiếp thông qua một đối tượng trung gian.
- Observer cho phép người nhận đăng ký động và hủy đăng ký nhận yêu cầu.
Bài viết đã giải thích về Observer Design Pattern. Hy vọng nội dung này hữu ích cho các bạn. Nếu bạn quan tâm, hãy khám phá thêm Series Design Patterns - Trợ thủ đắc lực của Developers của mình!!
Tài liệu tham khảo:
- Refactoring.Guru. https://refactoring.guru/design-patterns
- Design Patterns for Dummies, Steve Holzner, PhD
- Head First, Eric Freeman
- Gang of Four Design Patterns 4.0
- Dive into Design Pattern