Design pattern trong Java: Observer

Khái niệm

Observer là một design pattern thuộc loại Behavioral pattern(Hành vi) cho phép bạn xác định cơ chế đăng ký để thông báo cho nhiều đối tượng về bất kỳ sự kiện nào xảy ra với đối tượng mà họ đang quan sát.

Bài toán?

Hãy tưởng tượng rằng bạn có hai loại đối tượng: Khách hàng và cửa hàng. Khách hàng rất quan tâm đến một thương hiệu sản phẩm cụ thể (giả sử nó là một mẫu iphone mới) sẽ sớm có mặt trong cửa hàng.

Khách hàng có thể ghé thăm cửa hàng mỗi ngày và kiểm tra tính sẵn có của sản phẩm. Nhưng trong khi sản phẩm vẫn đang trong quá trình vận chuyển thì có vẻ khách hàng cũng khá là mất công khi phải đến cửa hàng hằng ngày.

Đến cửa hàng vs gửi spam

Mặt khác, cửa hàng có thể gửi hàng tấn email (có thể coi là spam) cho tất cả khách hàng mỗi khi có sản phẩm mới. Điều này sẽ giúp cho khách hàng tránh khỏi những chuyến đi tới cửa hàng mà không mua được sản phẩm. Đồng thời, nó sẽ làm khó chịu những khách hàng khác không quan tâm đến sản phẩm mới.

Điều này sẽ dẫn đến một xung đột. Khách hàng lãng phí thời gian để kiểm tra tính sẵn có của sản phẩm hoặc cửa hàng lãng phí nguồn lực để thông báo sai cho khách hàng.

Giải pháp

Đối tượng có một số trạng thái được gọi là Subject, nhưng vì nó cũng sẽ thông báo cho các đối tượng khác về những thay đổi của nó, nên nó cũng sẽ là Publisher. Tất cả đối tượng khác muốn theo dõi các thay đổi đối với trạng thái của Publisher được gọi là Subscribers.

Observer pattern gợi ý rằng bạn nên thêm cơ chế đăng ký vào các publisher class để các đối tượng riêng lẻ có thể đăng ký hoặc huỷ đăng ký khỏi luồng sự kiện đến từ publisher. Mọi thứ cũng không khó như bạn tưởng tượng. Trên thực tế, cơ chế này bao gồm field để lưu trữ danh sách Subscribers và một số public method cho phép thêm người đăng ký và xoá họ khỏi danh sách đó.

Cơ chế đăng ký cho phép các đối tượng riêng lẻ nhận thông báo sự kiện

Giờ đây, bất cứ khi nào một sự kiện quan trọng xảy ra với Publisher, publisher sẽ xem sét các subscribers và gọi phương thức thông báo cụ thể đến các đối tượng của họ.

Các ứng dụng thực tế có thể có hàng chục class subcribers khác nhau quan tâm đến việc theo dõi các sự kiện thay đổi của cùng một publisher. Bạn không thể ghép publisher đến tất các subcribers. Thậm chí, bạn có thể không biết trước những class nào đăng kí đến publisher.

Đó là lý do tại sao điều quan trọng là tất cả subcribers phải triển khai cùng một interface. Interface này nên khai báo method thông báo cùng với tập hợp các tham số cùng các trạng thái thay đổi.

Publisher thông báo cho subcripber bằng cách gọi phương thức thông báo cụ thể trên các object của họ.

Kiến trúc

  1. Publisher đưa ra các sự kiện mà đối tượng khác quan tâm. Những sự kiện này xảy ra khi publisher thay đổi trạng thái hoặc thực hiện một số hành vi. Publisher cho phép người đăng kí tham gia và người đăng kí rời khỏi danh sách.
  2. Khi một sự kiện mới xảy ra, publisher xem qua danh sách đăng ký và gọi phương thức thông báo được khai báo trong interface subcriber trên từng đối tượng đăng ký.
  3. Subcriber interfacce khai báo interface thông báo. Trong hầu hết trường hợp, nó bao gồm một phương pháp cập nhật duy nhất. Phương thức có thể có một số tham số cho phép publisher chuyển một số chi tiết khi thay đổi trạng thái.
  4. Subcribers cụ thể thực hiện một số hành động để phản hồi lại các thông báo do publisher đưa ra. Tất cả các class này phải implement cùng một interface để publisher không kết hợp với các subcribers cụ thể.
  5. Thông thường, subcriber cần một số thông tin của context để xử lý cập nhật chính xác. Cho nên, publisher thường chuyển một số dữ liệu context để làm đối số của phương thức thông báo.
  6. Khách hàng tạo ra publisher và subcriber cụ thể. Sau đó đăng ký subcriber cho các bản cập nhật của publisher.

Áp dụng khi nào?

Sử dụng Observer pattern khi các thay đổi đối với trạng thái của một đối tượng có thể yêu cầu thay đổi các đối tượng khác và tập đối tượng thực tế không biết trước các thay đổi đó.

Sử dụng khi một số đối tượng trong ứng dụng của bạn phải quan sát những đối tượng khác, như chỉ trong giới hạn thời gian hoặc trong các trường hợp cụ thể.

Cách triển khai

  1. Xem qua logic business và cố gắng chi nó thành hai phần: Core function, độc lập với code khác, sẽ đóng vai trò như là publisher. Phần còn lại sẽ thành tập hợp subcribers.
  2. Khai báo một interface Subcribes. Tối thiểu cần phải có một phương thức cập nhật.
  3. Khai báo interface của publisher và có phương thức thêm đối tượng vào danh sách đăng ký và xoá khỏi danh sách.
  4. Quyết định nơi đặt danh sách subcribe. Thông thường, code giống với tất cả các publisher. Publisher cụ thể có thể mở rộng lớp đó, kế thừa hành vi đăng ký.
  5. Tạo các class publisher cụ thể. Mỗi khi có điều gì quan trọng xảy ra, publisher phải thông báo cho tất cả những subcribers.
  6. Thực hiện các phương pháp thông báo cập nhật trong các subcriber cụ thể. Hầu hết sẽ cần context về sự kiện. Nó có thể chuyển như một đối số có phương thức thông báo.
  7. Khách hàng phải tạo tất cả những subcribers cần thiết và đăng ký cho họ các publisher phù hợp.

Ưu và nhược điểm

  • Nguyên tắc Open/Close. Bạn có thể giới thiệu các class subcribers mới mà không cần phải thay đổi lại code của publisher và ngược lại.
  • Bạn có thể thiết lập quan hệ giữa các đối tượng trong thời gian chạy
  • Subcribers được thông báo theo thứ tự ngẫu nhiên.

Demo

Các bạn có thể tham khảo demo Design Pattern Observer ở đây nhé 

Như vậy là mình vừa mới giới thiệu thêm một Design Pattern nữa. Nếu có bất cứ điều gì không hiểu thì các bạn hãy comment phía dưới. Chúc các bạn có ngày học tập hiệu quả, và đừng quên tham gia Group để trao đổi kiến thức nhiều hơn nhé.

3 1 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x