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.

C# có sẵn cơ chế này là event, đã gặp ở bài Sự kiện của khoá WinForms: nút là bên phát event Click, handler gắn bằng += là bên nghe.

Ví dụ

var service = new OrderService();
service.OrderPlaced += (sender, code) =>
    Console.WriteLine("Gửi email cho " + code);
service.OrderPlaced += (sender, code) =>
    Console.WriteLine("Cộng điểm cho " + code);

service.Place("DH1");

public class OrderService
{
    public event EventHandler<string>? OrderPlaced;

    public void Place(string code)
    {
        Console.WriteLine("Đã lưu " + code);
        OrderPlaced?.Invoke(this, code);
    }
}
  • event EventHandler<string>? khai báo một event gửi kèm một string, ở đây là mã đơn. Handler nhận sender (bên phát) và giá trị đó.
  • OrderPlaced?.Invoke(this, code) gọi lần lượt mọi handler. Chưa có handler nào thì event là null, và ?. (bài null và nullable) bỏ qua lời gọi.
  • 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 += ở ngoài.
OrderService: OrderPlaced 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 phần câu lệnh:

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

Handler chạy theo thứ tự đăng ký. lonely không có handler nào, ?. bỏ qua lời gọi nên không lỗi.

Lỗi hay gặp

Gọi event mà không có ?.. Chưa ai đăng ký thì event là null, gọi thẳng ném NullReferenceException.

// SAI — không có handler là NullReferenceException
public class OrderService
{
    public event EventHandler<string>? OrderPlaced;

    public void Place(string code)
    {
        OrderPlaced(this, code);
    }
}
// ĐÚNG — chỉ gọi khi có người nghe
public class OrderService
{
    public event EventHandler<string>? OrderPlaced;

    public void Place(string code)
    {
        OrderPlaced?.Invoke(this, code);
    }
}

Tóm tắt

  • Observer: bên phát thông báo, nhiều bên nghe tự phản ứng.
  • Trong C#, dùng event để phát và += để đăng ký.
  • 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.
  • Phát event bằng ?.Invoke để không lỗi khi chưa ai nghe.

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

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

Câu 3

Place gọi OrderPlaced?.Invoke(this, code) 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