1. 程式人生 > >Android開發之設計模式-觀察者模式

Android開發之設計模式-觀察者模式

觀察者模式(Observer Pattern)

定義:定義物件間的一種一對多的依賴關係,當一個物件的狀態發生改變時,所有依賴於它的物件都得到通知並被自動更新。

主要解決:一個物件狀態改變給其他物件通知的問題,而且要考慮到易用和低耦合,保證高度的協作。

何時使用:一個物件(目標物件)的狀態發生改變,所有的依賴物件(觀察者物件)都將得到通知,進行廣播通知。

如何解決:使用面向物件技術,可以將這種依賴關係弱化。

關鍵程式碼:在抽象類裡有一個 ArrayList 存放觀察者們。

應用例項: 1、拍賣的時候,拍賣師觀察最高標價,然後通知給其他競價者競價。 2、西遊記裡面悟空請求菩薩降服紅孩兒,菩薩灑了一地水招來一個老烏龜,這個烏龜就是觀察者,他觀察菩薩灑水這個動作。

優點: 1、觀察者和被觀察者是抽象耦合的。 2、建立一套觸發機制。

缺點: 1、如果一個被觀察者物件有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。 2、如果在觀察者和觀察目標之間有迴圈依賴的話,觀察目標會觸發它們之間進行迴圈呼叫,可能導致系統崩潰。 3、觀察者模式沒有相應的機制讓觀察者知道所觀察的目標物件是怎麼發生變化的,而僅僅只是知道觀察目標發生了變化。

使用場景:

  • 一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這些方面封裝在獨立的物件中使它們可以各自獨立地改變和複用。
  • 一個物件的改變將導致其他一個或多個物件也發生改變,而不知道具體有多少物件將發生改變,可以降低物件之間的耦合度。
  • 一個物件必須通知其他物件,而並不知道這些物件是誰。
  • 需要在系統中建立一個觸發鏈,A物件的行為將影響B物件,B物件的行為將影響C物件……,可以使用觀察者模式建立一種鏈式觸發機制。

注意事項: 1、JAVA 中已經有了對觀察者模式的支援類。 2、避免迴圈引用。 3、如果順序執行,某一觀察者錯誤會導致系統卡殼,一般採用非同步方式。

觀察者模式可以說用的比較多,比如天氣預報服務,你訂閱了本地的天氣,每天一旦天氣資訊更新,它就會及時傳送最新的天氣資訊。再比如,雜誌的訂閱,你只需向郵局訂閱雜誌,繳納一定的費用,當有新的雜誌時,郵局會自動將雜誌送至你預留的地址。

以上例子有一個共同點,就是我們無需每時每刻關注我們感興趣的東西,我們只需做的就是訂閱感興趣的事物,比如天氣預報服務,雜誌等,一旦我們訂閱的事物發生變化,比如有新的天氣預報資訊,新的雜誌等,被訂閱的事物就會即時通知到訂閱者,即我們。而這些被訂閱的事物可以擁有多個訂閱者,也就是一對多的關係。當然,嚴格意義上講,這個一對多可以包含一對一,因為一對一是一對多的特例。

現在你反過頭來看看觀察者模式的定義,你是不是豁然開朗了。

觀察者,我們稱它為Observer,有時候我們也稱它為訂閱者,即Subscriber

被觀察者,我們稱它為Observable,即可以被觀察的東西,有時候還會稱之為主題,即Subject

例項:

1、定義一個Weather實體類

public class Weather {//天氣實體類
    private String description;
    public Weather(String description){
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public String toString() {
        return "Weather{" +
                "description='" + description + '\'' +
                '}';
    }
}

2、定義觀察者

我們想要這個被觀察者能夠通用,將其定義成泛型。內部應該暴露register和unregister方法供觀察者訂閱和取消訂閱,至於觀察者的儲存,直接用ArrayList即可,此外,當有主題內容傳送改變時,會即時通知觀察者做出反應,因此應該暴露一個notifyObservers方法,以上方法的具體實現見如下程式碼。

import java.util.ArrayList;
import java.util.List;

public class Observable <T>{

    List<Observer<T>> mObservers = new ArrayList<Observer<T>>();
    public void register(Observer<T> observer){
        if (observer == null){
            throw new NullPointerException("observer == null");
        }
        synchronized (this){
            if(!mObservers.contains(observer)){
                mObservers.add(observer);
            }
        }
    }

    public synchronized void unregister(Observer<T> observer){
        mObservers.remove(observer);
    }
    public void notifyObserver(T data){
        for (Observer<T> observer:mObservers) {
            observer.onUpdate( this,data);
        }
    }
}

3、我們的觀察者,只需要實現一個觀察者的介面Observer,該介面也是泛型的。其定義如下

public interface Observer<T> {
    void onUpdate(Observable<T> observable,T data);
}

一旦訂閱的主題傳送變換就會回撥該介面。

我們來使用一下,我們定義了一個天氣變換的主題,也就是被觀察者,還有兩個觀察者觀察天氣變換,一旦變換了,就打印出天氣資訊,注意一定要呼叫被觀察者的register進行註冊,否則會收不到變換資訊。而一旦不敢興趣了,直接呼叫unregister方法進行取消註冊即可

public class Main {
    public static void main(String[] args) {
        Observable<Weather> observable = new Observable<Weather>();
        Observer<Weather> observer1 = new Observer<Weather>() {
            @Override
            public void onUpdate(Observable<Weather> observable, Weather data) {
                System.out.println("觀察者1 :" +data.toString());
            }
        };
        Observer <Weather> observer2 = new Observer<Weather>() {
            @Override
            public void onUpdate(Observable<Weather> observable, Weather data) {
                System.out.println("觀察者2 :" +data.toString());
            }
        };

        observable.register(observer1);
        observable.register(observer2);

        Weather weather=new Weather("晴轉多雲");
        observable.notifyObserver(weather);

        Weather weather1=new Weather("多雲轉陰");
        observable.notifyObserver(weather1);

        observable.unregister(observer1);

        Weather weather2=new Weather("颱風");
        observable.notifyObserver(weather2);


    }
}

輸出結果:

EventBus中的觀察者模式:觀察者模式的三個典型方法它都具有,即註冊,取消註冊,傳送事件

EventBus.getDefault().register(Object subscriber);
EventBus.getDefault().unregister(Object subscriber);

EventBus.getDefault().post(Object event);

RxJava

建立一個被觀察者

Observable<String> myObservable = Observable.create(  
    new Observable.OnSubscribe<String>() {  
        @Override  
        public void call(Subscriber<? super String> sub) {  
            sub.onNext("Hello, world!");  
            sub.onCompleted();  
        }  
    }  
);

建立一個觀察者,也就是訂閱者

Subscriber<String> mySubscriber = new Subscriber<String>() {  
    @Override  
    public void onNext(String s) { System.out.println(s); }  
  
    @Override  
    public void onCompleted() { }  
  
    @Override  
    public void onError(Throwable e) { }  
};

觀察者進行事件的訂閱

myObservable.subscribe(mySubscriber);

以上既為觀察者模式的簡介,詳解見連結:

https://wenku.baidu.com/view/662028d0360cba1aa811da52.html?st=1

 觀察者模式在Android中被應用的很是頻繁,包括一些優秀的開源框架都會用到,下篇我們開始學習一些Android中常用的一些開源框架,學習下其中的核心思想,看懂別人的程式碼到運用別人的程式碼,再到優化別人的程式碼,這段路程還很長,還需要很多的努力。

待續...