Observer Pattern - Mô Hình Mối Quan Hệ Một Và Nhiều

Observer Pattern - Mô Hình Mối Quan Hệ Một Và Nhiều

Một dự án phần mềm với cấu trúc rõ ràng, dễ hiểu sẽ tiết kiệm được rất nhiều công sức và tiền bạc. Gang of Four viết ra 23 design pattern nhằm giúp các developer có hướng đi rõ ràng để thiết kế phần mềm hoàn chỉnh.
23 design patterns chia làm 3 patterns lớn là:

  • Creation
  • Structure
  • Behavior

Hôm nay, mình muốn giới thiệu một trong những pattern phổ biến và thường gặp nhất: Observer pattern

Observer pattern là gì?

Trong một thế giới hướng dữ liệu như hiện nay, bất kỳ một sự kiện nhỏ nào cũng mau chóng được lan ra và cập nhật liên tục. Ví dụ như cún cưng của siêu sao A rụng lông vào mùa hè, cầu thủ B tè bậy có mùi thơm hay thậm chí ca sĩ C mặc đồ bộ khi đi chợ...v...v.

Hằng ngày, chúng ta dỏng tai lên nghe mọi tin tức đến từ vô số nguồn: báo, sách, facebook, tiktok, email, truyền miệng, loa phường. Giữa ma trận dữ liệu ấy, mỗi người cần phải chắt lọc, tìm kiếm thông tin đáng giá, rồi hành động tương ứng.

Vô hình chung, chúng ta đã tham gia vào Observer pattern với các vai trò khác nhau.

Observer pattern là một mẫu thiết kế phần mềm mà một đối tượng, gọi là subject, duy trì một danh sách các thành phần phụ thuộc nó, gọi là observer, và thông báo tới chúng một cách tự động về bất cứ thay đổi nào.

Như trong ví dụ ở trên:

Observable (Subject): Nguồn sự kiện, tin tức.

Observer: Mọi người tiếp nhận sự kiện, tin tức và xử lý.

Lập trình hướng đối tượng là lấy những sự vật, sự việc ở đời thực rồi cụ thể hóa tương ứng thông qua các class, method. Mặt khác cũng phải đảm bảo behavior (hành vi) của các sự vật, sự việc đó phải phù hợp với ngữ cảnh được đưa ra. Như vậy, code mới dễ hiểu và dễ đọc.

Vậy chúng ta nên implement Observer pattern như thế nào đây?

Observer pattern hoạt động thế nào?

Hãy bắt đầu từ những thứ đơn giản. Giả sử chúng ta có 1 hotgirl và một đám con trai crush cô ấy. Hiển nhiên, mỗi lần cô ta hắt hơi, sổ mũi, đăng status than ế thì cả đám lập tức sồn sồn lên. Ở trường hợp này, cô gái chính là Subject, đám nam nhi kia là Observer, sự kiện cho là post facebook đi. Đầu vào đã đủ, tiến hành làm thôi!

public class HotGirl
{
    private bool needAttention = false;

    // Some of boys crushing this instance :))
    public IList<Boy> FriendZone = new List<Boy>();

    public void PostFacebook()
    {
        Console.WriteLine("Complete post");
        NeedAttention = true;
    }

    // State of instance. When state change, observe will know and react
    private bool NeedAttention
    {
        get => needAttention;
        set
        {
            needAttention = value;
            Notify();
        }
    }

    public void Notify()
    {
        foreach (var b in FriendZone)
        {
            b.Care();
        }
    }

    // Register observer. 
    public void AddToZone(Boy b)
    {
        FriendZone.Add(b);
    }
}

public class Boy
{
    public string Name;

    public Boy(string name)
    {
        Name = name;
    }

    public void Care()
    {
        Console.WriteLine($"{Name}: Are you OK?");
    }
}

Những class khá đơn giản. Cô nàng bình thường sẽ yên ổn làm người, cho đến khi cảm thấy chán đời (needAttention = true) thì sẽ thay đổi trạng thái của mình bằng cách đăng hình, status thả thính lung tung. Và đám con trai ảo tưởng sức mạnh trong FriendZone sẽ rất hăng hái mà đáp trả lại với method Care() sau khi nhận được tín hiệu.

Đoạn code dưới đây sẽ miêu tả một tình huống ngoài đời thực:

static void Main(string[] args)
{
    // Create a girl instance as subject (publisher)
   var sexyGirl = new HotGirl();

    //// Add 2 boys to her friend zone.
    sexyGirl.AddToZone(new Boy("ATSM1"));
    sexyGirl.AddToZone(new Boy("ATSM2"));

    // One day. She need some attention, so she post to facebook.
    // After she complete post facebook. These poor boys react.
    sexyGirl.PostFacebook();
    Console.ReadKey();
}

Như code và hình đã thể hiện, trong hàm Main(), chúng ta không sử dụng phương thức nào của class Boy cả, những dòng tin nhắn quan tâm: "Are you OK?" là đến từ việc cô gái đã post 1 bài viết lên Facebook.

Sẽ có những thắc mắc đại loại như: Sao phiền phức, mất công quá vậy? Call trực tiếp phương thức của class Boy trong hàm Main() luôn đi? Hay sao không sử dụng method Care() trong hàm PostFacebook() mà làm get, set chi cho dài dòng?

Bởi vì, cái chúng ta cần là hiện thực hóa sự việc thông qua code, rõ ràng khi bạn implement theo design pattern, những tiến trình, tình huống thực tế xảy ra thế nào thì trong code biểu hiện thế ấy. Cô gái chỉ cần post nhẹ 1 bài viết là những chàng trai trong list friend lập tức phản hồi mà không cần có sự tác động từ bên ngoài.

Mở rộng ra, PostFacebook() chỉ là 1 trong rất nhiều cách gây sự chú ý, 1 cô gái có bao nhiêu cách thả thính cơ chứ? Chẳng lẽ cứ 1 cử chỉ, hành động bạn lại duplicate code vòng for? Nếu bạn là 1 developer phải làm dự án maintain, mình tin chắc bạn sẽ rất vui khi biết rằng: "Chỉ cần thay đổi value của biến needAttention, các observer (boys) sẽ lập tức phản hồi. Không phải lọ mọ ngồi mò source code". Các bạn cũng dùng qua các framework, thư viện nổi tiếng thì đều sẽ có cảm giác đoán ra được method, variable tiếp theo mà mình cần, dù thậm chí đây là lần đầu bạn sử dụng, bởi chúng được tổ chức quá tốt. 

Kết luận:

Design pattern là để chúng ta code tốt hơn: Dễ hiểu, dễ maintain, có tổ chức. Observer pattern rất phổ biến ngoài đời thực: 

  • Định nghĩa mối phụ thuộc một - nhiều giữa các đối tượng để khi mà một đối tượng có sự thay đổi trạng thái, tất các thành phần phụ thuộc của nó sẽ được thông báo và cập nhật một cách tự động.
  • Một đối tượng có thể thông báo đến một số lượng không giới hạn các đối tượng khác.

Hãy nắm vững nó và implement cho sát với tình huống thực tế. Chúc các bạn ngày càng tốt lên!