VieTopik
Tiếng HànTiếng AnhIT
  • Góc học tập
Tải app
  • Thư viện
  • Luyện thi
  • Cẩm nang
  • Góc học tập
Kiến trúc và chất lượng codeDesign pattern
Bài 14/17
5 phút

Observer

Nội dung bài · 5 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt

Đặt hàng xong phải gửi email, cộng điểm thành viên, gửi SMS. Nếu OrderService tự gọi cả ba, mỗi việc mới lại phải sửa OrderService, và nó phải biết mọi phần khác của hệ thống. Với Observer, OrderService chỉ thông báo "đã đặt hàng", việc nào cần thì tự đăng ký nghe.

Khái niệm

📣 Observer: một object phát thông báo khi có việc xảy ra, các object khác đăng ký nghe và tự xử lý, bên phát không cần biết ai đang nghe.

Java không có từ khoá riêng cho việc này. Bên nghe là một listener: object implement một interface do bên phát đặt ra. Bên phát giữ danh sách listener và gọi lần lượt từng cái.

Ví dụ

// Main.java
void main() {
    var service = new OrderService();
    service.addListener(code ->
        System.out.println("Gửi email cho " + code));
    service.addListener(code ->
        System.out.println("Cộng điểm cho " + code));

    service.place("DH1");
}

// OrderPlacedListener.java
interface OrderPlacedListener {
    void onOrderPlaced(String code);
}

// OrderService.java
import java.util.*;

class OrderService {
    private final List<OrderPlacedListener> listeners =
        new ArrayList<>();

    public void addListener(OrderPlacedListener l) {
        listeners.add(l);
    }

    public void place(String code) {
        System.out.println("Đã lưu " + code);
        for (OrderPlacedListener l : listeners) {
            l.onOrderPlaced(code);
        }
    }
}
  • OrderPlacedListener là interface chỉ có một method, nhận mã đơn. Interface như vậy viết object implement nó gọn bằng lambda, như Function ở bài Lambda.
  • place gọi lần lượt mọi listener trong danh sách, theo thứ tự đăng ký.
  • OrderService ở đây là bản rút gọn, chỉ giữ phần thông báo. Nó không biết gì về email hay điểm. Thêm việc gửi SMS là thêm một addListener ở ngoài.
OrderService: place Gửi email Cộng điểm Gửi SMS
OrderService phát một thông báo, nhiều bên cùng nghe

Thử ngay

Chạy ví dụ, rồi thêm hai dòng sau vào cuối main:

var lonely = new OrderService();
lonely.place("DH2");

Đoán trước khi chạy: toàn bộ chương trình in ra những dòng nào? Đơn DH2 không có ai nghe thì có lỗi không?

Xem kết quả
Đã lưu DH1
Gửi email cho DH1
Cộng điểm cho DH1
Đã lưu DH2

Listener chạy theo thứ tự đăng ký. lonely có danh sách listener rỗng, vòng for không chạy lần nào nên không lỗi.

Lỗi hay gặp

Quên tạo danh sách listener. Field chưa gán thì là null, chưa ai đăng ký mà gọi place là ném NullPointerException.

// SAI — không có listener là NullPointerException
// OrderService.java
import java.util.*;

class OrderService {
    private List<OrderPlacedListener> listeners;

    public void place(String code) {
        for (OrderPlacedListener l : listeners) {
            l.onOrderPlaced(code);
        }
    }
}
// ĐÚNG — danh sách rỗng có sẵn từ đầu
// OrderService.java
import java.util.*;

class OrderService {
    private final List<OrderPlacedListener> listeners =
        new ArrayList<>();

    public void place(String code) {
        for (OrderPlacedListener l : listeners) {
            l.onOrderPlaced(code);
        }
    }
}

Tóm tắt

  • Observer: bên phát thông báo, nhiều bên nghe tự phản ứng.
  • Trong Java, bên nghe implement một interface listener, đăng ký bằng addListener.
  • Bên phát không biết bên nghe, thêm việc mới không phải sửa bên phát.
  • Tạo sẵn danh sách listener rỗng để không lỗi khi chưa ai nghe.
  • Giữa các bean, Spring có sẵn ApplicationEventPublisher và @EventListener làm đúng việc này.

Tự kiểm tra

0/3 câu
Câu 1

Thêm việc "gửi SMS khi đặt hàng" với Observer. Cần sửa OrderService không?

Câu 2

Listener gửi email đăng ký trước và ném exception. Listener cộng điểm đăng ký sau nó có chạy không?

Câu 3

place gọi các listener trước dòng lưu đơn vào database. Rủi ro là gì?

DecoratorChia tầng

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Thử ngay
  4. 4.Lỗi hay gặp
  5. 5.Tóm tắt