Thứ Ba, 25 tháng 12, 2018

Observer Pattern

Với loại Pattern này, mình sẽ đưa ra tình huống trước. Ví dụ bạn đang làm 1 cái web dự báo thời tiết chẳng hạn. Trang web của bạn bắt buộc phải có thông tin thời tiết rồi đúng ko? Vậy là ta có 1 đối tượng gọi là "Weather". Đối tượng Weather này có 1 biến tên là "Temperature", giá trị biến này sẽ có sự thay đổi theo thòi gian. Ví dụ đêm lạnh ngày nóng chẳng hạn. Okie! Trang web của bạn để trực quan hơn thì nên có 1 cái biểu đồ để thể hiện nhiệt độ. Vậy nên ta có 1 đối tượng mới là "Chart". Nhiệm vụ của "Chart" là mỗi khi nhiệt độ thay đổi thì "Chart" sẽ vẽ lên 1 điểm mới trên biểu đồ.
Vậy để giải quyết bài toán này thì ta làm thế nào? Rất đơn giản, từ đối tượng "Chart", ta sẽ liên tục cập nhật "Temperature" của "Weather". Nếu như Temperature thay đổi, thì Chart sẽ thực hiện việc vẽ lên 1 điểm ở biểu đồ.
Okie! Nhìn có vẻ ổn đúng không? Nhưng sau một hồi ngẫm nghĩ, bạn lại muốn có thêm 1 cái bảng thống kê ghi lại những giá trị và thời gian thay đổi của Temperature. Vậy là bạn lại tạo ra 1 đối tượng "Table", và cũng làm y như "Chart" là cập nhật giá trị "Temperature".
Rồi bạn lại nhận ra, nên có thêm 1 hình animation thể hiện mức độ nóng hay lạnh ở thời điểm hiện tại, và bạn lại tạo 1 đối tượng "Animation". Đối tượng này bạn làm y hệt 2 đối tượng "Table" và "Chart". Cứ sau mỗi 1 phút, 3 đối tượng "Table", "Chart" và "Animation" lại gửi request cho "Weather" để cập nhật. Lúc này, bạn đã thấy có gì đó sai sai chạm môi bạn rồi đấy.
 Nhưng nhu cầu thông tin về thời tiết không chỉ có nhiệt độ, nó còn có về độ ẩm, về gió, về lượng mưa.... Thế nên, bạn lại thêm vào những biến "Wind", "Rain".... cho "Weather". Và tất nhiên, những đối tượng "Chart", "Table", "Animation" cũng nên cập nhật sư thay đổi của những thông số mới này. Và chính ngay lúc này đây, chi phí cho việc cập nhật giá trị quá lớn đã làm cho chương trình của bạn bị chậm đi. Nhưng chưa dừng lại ở đó, nhiều khách hàng còn muốn có thêm những tính năng khác như bản đồ thời tiết, lời khuyên thời tiết... Và vấn đề bạn chắc chắn sẽ gặp phải nếu cứ tiếp tục design theo cách này là tài nguyên của web bạn rất lớn và có thể bị crash. Và chính lúc này đây, bạn phải cần dùng đến observer pattern.
 Đơn giản là từ cách suy nghĩ "Pull", bạn phải suy nghĩ theo hướng "Push". Tức là, mỗi lần Temperature thay đổi giá trị, Weather sẽ tự động Push thông báo cho Chart , Table, Animation. Và theo kiểu suy nghĩ thiết kế này, chúng ta sẽ ko phải tốn tài nguyên cho việc liên tục gửi request để cập nhật nữa. Vậy để Weather biết phải thông báo cho ai khi Temperature thay đổi, thì những đối tượng như Chart, Table và Animation cần phải đăng kí vào Weather để nó còn biết mà la làng lên chứ. Đúng ko?
 Vậy, định nghĩa của observer Pattern là gì?
Observer Pattern: định nghĩa mối quạn hệ one-to-many giữa nhứng đối tượng với nhau. Sao cho, mỗi khi 1 đối tượng thay đổi, thì những đối tượng quan hệ với nó sẽ được thông báo và cập nhật tự động
Okie! Vậy thì chúng ta thực hiện Observer pattern như lào? Khái niệm thì có rồi đấy, nhưng mần như lào mới quan trọng. Trên mạng h có rất nhiều mô hình để hiện thực hóa cái loại pattern này, và mình chỉ lấy 1 cái ra để xài thôi. Nó sẽ được mần như lày:
Đầu tiên, bạn tạo 1 interface Observable , đây là cái interface cho những đối tượng như Weather trong ví dụ ấy. Interface này sẽ gồm các hàm chính như : add, remove và notify. Tiếp theo, bạn tạo 1 interface Observer cho những đối tượng cần được cập nhập ( như là Chart, Table, Animation). Interface này sẽ có hàm update.
Bây giờ, ta tạo 2 hiện thực cho 2 interface này. Mình sẽ tạo hiện thực Weather và Chart. Trong đó, Weather mình sẽ cho thêm 1 hàm là getTemperature(). Hàm này sẽ giúp cho Chart có thể lấy được thông tin mỗi khi cần dùng để update.
Vậy thôi, đó chính là mô hình dùng để hiện thực hóa Observer Pattern. Bây giờ, ta chỉ cần đăng kí Chart vào trong Weather bằng cách chạy hàm add(). Sau đó, mỗi lần temperature mà đổi, thì Weather sẽ chạy hàm notify(), hàm này sẽ chạy hàm update() của Chart. Vậy là xong, rất i zì.
Và giờ mình sẽ thêm tí code cho sinh động, cho mấy bro nghiền code có cái mà đọc nhá. Đầu tiên là tạo 2 cái interface cho observable và observer.
public interface IObservable{
    public void add(IObserver o);
    public void remove(IObserver o);
    public void notify();

}

public interface IObserver {
    public void update();
}
Sau đó mình tạo 2 hiện thực cho 2 cái interface này, đó là Weather và Chart.
public class Weather{
    private List listObservers = new ArrayList();
    private int temperature;
    public void add(IObserver o) {
         this.listObservers.add(o);
    }
    public void remove(IObserver o) {
         this.listObservers.remove(o);
    }
    public void notify() {
         for(IObserver o : listOBservers) {
              o.update();
         }
    }
    public int getTemperature() {
         return this.temperature;
    }
}

public class Chart{
    private Weather weather;
    public Chart(Weather weather){
        this.weather = weather;
    }
    public void update() {
         System.out.println("them 1 diem tren bieu do voi gia tri la: " + this.weather.getTemperature());
    }
}
Vậy là xong, h chỉ cần khởi tạo 2 đối tượng Weather và Chart là tắt máy đi ngủ được rồi.
Weather weather = new Weather();
Chart chart = new Chart(weather);
weather.add(chart);
Share:

0 nhận xét:

Đăng nhận xét

Được tạo bởi Blogger.