1. 程式人生 > >教你寫響應式框架(一)

教你寫響應式框架(一)

在真正開始編寫自己的響應式框架之前,我們先來從觀察者模式說起。已經對觀察者模式很熟悉的可以直接掠過。

基本概念

觀察者模式屬於物件行為模式之一,也可叫做釋出——訂閱模式。它定義了一種以對多的依賴關係,讓多個觀察者(訂閱者)同時觀察(監聽)一個被觀察者(主題),當被觀察者的狀態發生變化時,會通知所有的觀察者物件。

在我們瞭解什麼是觀察者模式之後,我們來看一下觀察者模式的結構:
這裡寫圖片描述

通過上圖我們可以看出觀察者涉及到了四種角色:

  • 抽象主題角色(Subject):抽象主題角色儲存了所有註冊的觀察者的引用,同時提供了對觀察者的管理,抽象主題角色也叫做被觀察者(Observable)
  • 具體主題角色
    (ConcreteSubject):在具體主題內部狀態發生變化時,給所有註冊過的觀察這發出通知.
  • 抽象觀察者角色(Observer):為所有的具體觀察者定義的約束介面,在得到主題通知時更新自己.
  • 具體觀察者角色(ConcreteObserver):具體觀察者實現抽象觀察者角色,以便接受主題改變的狀態.

程式碼實現

現在我們來看一下程式碼的實現

抽象主題角色:

public abstract class Subject {
    private List<Observer> list = new ArrayList<>();

    //將observer註冊到Subject
public void attach(Observer observer) { list.add(observer); } //移除某個observer public void detach(Observer observer) { list.remove(observer); } //通知所有observer public void notifyObservers(String newState) { list.stream().forEach(ob->{ob.update(newState);}); } }

具體主題角色:

public class ConcreteSubject extends Subject {
    public void change(String state) {
        this.notifyObservers(state);
    }
}

抽象觀察者

public interface Observer {
    void update(String state);
}

具體觀察者

public class ConcreteObserver implements Observer {

    @Override
    public void update(String state) {
        System.out.println("主題狀態改變了:" + state);
    }
}

客戶端測試類:

public class Client {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        Observer observer = new ConcreteObserver();
        //將觀察者註冊到被主題(被觀察者)上
        subject.attach(observer);
        subject.change("1");

    }
}

到現在為止一個基本的觀察者模式已經實現了.

推模型和拉模型

在實際使用中,觀察者往往需要更多的有關主題的狀態,並且在專案的起始階段我們通常想不到以後的觀察者會需要觀察者的什麼資訊,那該如何解決呢?在解決這個問題之前,我們先來看一下觀察者模式的兩種模型:

  • 推模型:該模型假設主題物件知道觀察者需要的資料,雙方提前做好約定,以後需求變動的可能性較小.上面的例子就是典型的推模型:Observer只想知道Subject的狀態.
  • 拉模型:主題物件不能確定被觀察者到底需要什麼資訊,因此,直接將自己的引用傳給被觀察者,被觀察者根據自己需求通過主題的引用再去拉去資料.

瞭解完這兩種模型之後,我們已經有了解決上面提出的問題的方案了:採用拉模型來實現。

讓我們來看一下拉模型中的程式碼實現:
抽象主題角色:

public abstract class Subject {
    private List<Observer> list = new ArrayList<>();

    public void attach(Observer observer) {
        list.add(observer);
    }

    public void detach(Observer observer) {
        list.remove(observer);
    }

    public void notifyObservers() {
        list.stream().forEach(ob->{ob.update(this);});
    }

}

具體主題角色:

public class ConcreteSubject extends Subject {
    private String title;
    private String author;

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public void change(String title, String author) {
        this.title = title;
        this.author = author;
        this.notifyObservers();
    }
}

抽象觀察者:

public interface Observer {
    void update(Subject subject);
}

具體觀察者:

public class ConcreteObserver implements Observer {

    @Override
    public void update(Subject subject) {
        //根據需求通過subject獲取自己所需要的資訊
        System.out.println(((ConcreteSubject) subject).getAuthor());
        System.out.println(((ConcreteSubject) subject).getTitle());

    }
}

客戶端測試:

public class Client {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        Observer observer = new ConcreteObserver();
        subject.attach(observer);

        subject.change("java core", "ms");
    }
}

到現在為止你已經瞭解了觀察者模式,現在讓我們來回答一個簡單的問題,什麼時候需要用觀察者模式呢?
首先,我們要強調一點不是為了模式而模式,而是為了解決問題而模式。

觀察者模式非常適合於多個物件的變化依賴於某個物件的變化的這種情況。舉個例子:上課情況下,所有的學生的都是將注意力放在老師身上,當老師在講臺上移動時(主題狀態變化),學生的眼球的移動應該是跟隨老師的(觀察者根據主題的變化來變化)

到現在為止,你已經有了編寫響應式框架的基礎。那麼在下一篇中,我們將一步一步編寫自己的響應式框架。