[Design Patterns #7] Observer Pattern

Observer Pattern còn có thể gọi là Publish-Subscribe Pattern, là design pattern dùng để tạo ra mối quan hệ phụ thuộc one-to-many giữa các đối tượng, khi một đối tượng thay đổi trạng thái, tất cả các phụ thuộc của nó sẽ được thông báo và cập nhật tự động.

Hãy cùng nhau phân tích tình huống sau

– Sếp đến văn phòng team của tôi và nói: “Tôi vừa kiểm tra log và thấy ai đó vừa chỉnh sửa dữ liệu trong database , tại sao không thông báo cho tôi ?”

– Tôi: “Ý sếp là thế nào ? Sếp muốn được thông báo về mọi chỉnh sửa xảy ra với database à ?”

– Sếp: “Yes, tôi muốn nhận thông báo riêng mỗi khi có thay đổi trong database. Tôi muốn kiểm soát những gì đang diễn ra”.

– Tôi: “Tức là mỗi khi update database thì chúng tôi phải gửi cho sếp bản memo những điểm thay đổi ?”

– Sếp: “Đúng cmnr”

– Tôi: “OK, đơn giản. Tôi sẽ sử dụng Observer Pattern và đăng ký để sếp làm người quan sát cơ sở dữ liệu (database observer). Sếp sẽ nhận được thông báo tự động cho mỗi lần có update database. Chúng tôi không cần phải gửi memo cho sếp theo cách thủ công, tất cả sẽ được làm tự động, bằng code.

– Sếp: “Rất tốt. Triển luôn và ngay đi.”

Sếp của tôi muốn nhận thông báo mỗi khi có thay đổi đối với database của công ty. Và, khi phân tích kỹ, tôi thấy rằng chính tôi cũng có lúc cần tất cả những thông tin đó. Không chỉ vậy, những khách hàng thực hiện các thay đổi cũng nên được thông báo về sự thành công hay thất bại của những thay đổi đó. Như vậy, bây giờ chúng ta đã có tập hợp các “observer” – nhà quan sát – những người cần biết những gì đang diễn ra, Observer Pattern là cách tiếp cận rất phù hợp trong trường hợp này, nó cho phép một đối tượng (ở đây là database) thông báo cho một bộ quan sát viên (sếp, các lập trình viên, khách hàng) các thay đổi đã xảy ra. Bạn có thể thêm/xóa các đối tượng observer lúc runtime một cách linh hoạt. Khi một sự kiện xảy ra, tất cả các observer đã đăng ký sẽ được thông báo.

Let’s go. Chúng ta sẽ cùng vọc cụ thể hơn về Observer Pattern ngay bây giờ.

Cơ chế hoạt động của Observer Pattern

Observer cần phải đăng ký với Subject (đây là đối tượng mà Observer cần nhận thông tin về nó), trong bài toán mà chúng ta đang giải quyết thì Subject chính là database server → Một Subject có thể có nhiều Observer đăng ký nên Observer 2 cũng có thể đăng ký giống như Observer 1 →

Subject sẽ lưu thông tin về các tất cả các observer đã đăng ký. Khi có sự kiện xảy ra, subject sẽ thông báo (notify) đến tất cả các observer đã đăng ký →

Bất cứ lúc nào thì một observer đã đăng ký cũng có thể hủy đăng ký (unregister) để ngừng nhận thông báo từ subject →

Khi Observer 1 đã unregister thì nó sẽ không còn nhận được notification từ subject nữa. Lúc này chỉ còn Observer 2 nhận được notification →

Và bất cứ lúc nào thì Observer 1 cũng có thể register lại với subject để tiếp tục nhận notification.

Áp dụng Observer Pattern

Trong Observer Pattern, chúng ta sẽ cần phải define ra interface cho subject và observer, chúng sẽ làm việc với nhau thông quan interface mà không cần biết class cụ thể là gì. Điều này làm các class Loose Coupling với nhau, hệ thống dễ maintain và mở rộng.

*** Class diagram *** Tạo subject interface *** Tạo observer interface *** Tạo subject class

Subject phải cho phép các observer có thể đăng ký và nhận thông báo khi có sự kiện xảy ra. Theo subject interface thì 3 method mà subject class cần implement đó là registerObserver, removeObserver, notifyObservers. Đó là những gì mà Database class cần làm trong ví dụ này.

Để lưu thông tin về các observer thì ở đây mình sẽ dùng một biến member kiểu vector<IObserver*> mObservers. Khi muốn đăng ký một observer với subject thì cần call method registerObserver của subject và truyền vào pointer đến observer. Sau đó, subject – đối tượng của class Database sẽ call hàm pushback của vector để thêm pointer đó vào vector mObservers để quản lý

Khi muốn xóa một observer đã đăng ký thì tìm pointer của observer đó trong mObservers và xóa nó đi