設(shè)計模式之觀察者模式(Observer Pattern)

觀察者模式也叫發(fā)布/訂閱模式。

觀察者模式用于建立一種對象與對象之間的依賴關(guān)系,一個對象發(fā)生改變時將自動通知其他對象,其他對象將相應(yīng)作出反應(yīng)。在觀察者模式中,發(fā)生改變的對象稱為觀察目標(biāo),而被通知的對象稱為觀察者,一個觀察目標(biāo)可以對應(yīng)多個觀察者,而且這些觀察者之間可以沒有任何相互聯(lián)系,可以根據(jù)需要增加和刪除觀察者,使得系統(tǒng)更易于擴(kuò)展。一個軟件系統(tǒng)常常要求在某一個對象的狀態(tài)發(fā)生變化的時候,某些其他的對象做出相應(yīng)的改變。做到這一點(diǎn)的設(shè)計方案有很多,但是為了使系統(tǒng)能夠易于復(fù)用,應(yīng)該選擇低耦合度的設(shè)計方案。減少對象之間的耦合有利于系統(tǒng)的復(fù)用,但是同時設(shè)計師需要使這些低耦合度的對象之間能夠維持行動的協(xié)調(diào)一致,保證高度的協(xié)作。觀察者模式是滿足這一要求的各種設(shè)計方案中最重要的一種。

概念: 定義對象之間的一種一對多依賴關(guān)系,使得每當(dāng)一個對象狀態(tài)發(fā)生改變時,其相關(guān)依賴對象皆得到通知并被自動更新。觀察者模式的別名包括發(fā)布-訂閱(Publish/Subscribe)模式、模型-視圖(Model/View)模式、源-監(jiān)聽器(Source/Listener)模式或從屬者(Dependents)模式。觀察者模式是一種對象行為型模式。

觀察者模式結(jié)構(gòu)重要核心模塊:

抽象主題(Subject)

抽象主題角色把所有對觀察者對象的引用保存在一個聚集(比如ArrayList對象)里,每個主題都可以有任何數(shù)量的觀察者。抽象主題提供一個接口,可以增加和刪除觀察者對象,抽象主題角色又叫做抽象被觀察者(Observable)角色。

具體主題(ConcreteSubject)

將有關(guān)狀態(tài)存入具體觀察者對象;在具體主題的內(nèi)部狀態(tài)改變時,給所有登記過的觀察者發(fā)出通知。具體主題角色又叫做具體被觀察者(Concrete Observable)角色。

抽象觀察者(Observer)

為所有的具體觀察者定義一個接口,在得到主題的通知時更新自己,這個接口叫做更新接口。

具體觀察者(ConcreteObserver)

存儲與主題的狀態(tài)自恰的狀態(tài)。具體觀察者角色實(shí)現(xiàn)抽象觀察者角色所要求的更新接口,以便使本身的狀態(tài)與主題的狀態(tài)像協(xié)調(diào)。如果需要,具體觀察者角色可以保持一個指向具體主題對象的引用。

觀察者模式的推拉方式。

Java代碼例子

推方式:主題對象向觀察者推送主題的詳細(xì)信息,不管觀察者是否需要,推送的信息通常是主題對象的全部或部分?jǐn)?shù)據(jù)。

package com.zyh.designpatterns;

public interface Observer {

    public void update(String state);
}
package com.zyh.designpatterns;

public class ProgramMonkeyObserver implements Observer{
    @Override
    public void update(String state) {
        System.out.println("Programer look the SDK download process is " + state);
    }
}
package com.zyh.designpatterns;

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

public class Subject {

    private List<Observer> list = new ArrayList<Observer>();

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

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

    public void motifyObservers(String newState)
    {
        for(Observer observer : list)
        {
             observer.update(newState);
        }
    }
}
package com.zyh.designpatterns;

public class SDKDownloadSubject extends Subject {

    public void netProcessChange(String data)
    {
        this.motifyObservers(data);
    }
}
package com.zyh.designpatterns;

public class Main {

    public static void main(String[] args)
    {
       SDKDownloadSubject sdkDownloadSubject = new SDKDownloadSubject();
       Observer observer = new ProgramMonkeyObserver();
       Observer observer1 = new ProgramMonkeyObserver();
       sdkDownloadSubject.attach(observer);
       sdkDownloadSubject.attach(observer1);

       sdkDownloadSubject.netProcessChange("1%");
       sdkDownloadSubject.netProcessChange("51%");
       sdkDownloadSubject.netProcessChange("100%");
    }
}

運(yùn)行結(jié)果:

Programer look the SDK download process is 1%
Programer look the SDK download process is 1%
Programer look the SDK download process is 51%
Programer look the SDK download process is 51%
Programer look the SDK download process is 100%
Programer look the SDK download process is 100%

拉方式:主題對象在通知觀察者的時候,只傳遞少量信息。如果觀察者需要更具體的信息,由觀察者主動到主題對象中獲取,相當(dāng)于是觀察者從主題對象中拉數(shù)據(jù)。一般這種模型的實(shí)現(xiàn)中,會把主題對象自身通過update()方法傳遞給觀察者,這樣在觀察者需要獲取數(shù)據(jù)的時候,就可以通過這個引用來獲取了。

package com.zyh.designpatterns.ObserverPattern2;

public interface Observer {
    public void update(Subject subject);
}
package com.zyh.designpatterns.ObserverPattern2;

public class ProgramMonkeyObserver implements Observer{

    @Override
    public void update(Subject subject) {
        String state = ((SDKDownloadSubject)subject).getState();
        System.out.println("Programer look the SDK download process is: " + state);
    }
}
package com.zyh.designpatterns.ObserverPattern2;

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

public class Subject {

    private List<Observer> list = new ArrayList<Observer>();

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

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

    public void motifyObserver()
    {
        for (Observer observer : list)
        {
            observer.update(this);
        }
    }
}
package com.zyh.designpatterns.ObserverPattern2;

public class SDKDownloadSubject extends Subject{

    private String mState;

    public String getState()
    {
        return mState;
    }

    public void netProcessChange(String data)
    {
         mState = data;
         this.motifyObserver();
    }
}
package com.zyh.designpatterns.ObserverPattern2;

public class Main {

    public static void main(String[] args)
    {
        SDKDownloadSubject sdkDownloadSubject = new SDKDownloadSubject();
        Observer observer = new ProgramMonkeyObserver();
        sdkDownloadSubject.attach(observer);
        sdkDownloadSubject.netProcessChange("1%");
        sdkDownloadSubject.netProcessChange("51%");
        sdkDownloadSubject.netProcessChange("100%");
    }
}
Java標(biāo)準(zhǔn)支持的觀察者模式

在Java語言的java.util庫里面,提供了一個Observable類以及一個Observer接口,構(gòu)成了Java語言對觀察者模式的支持。

Observer接口只定義了一個update()方法,當(dāng)被觀察者對象的狀態(tài)發(fā)生變化時,被觀察者對象的notifyObservers()方法就會調(diào)用這一方法。

Observable類是被觀察者類的基類。java.util.Observable提供公開的方法支持觀察者對象,這些方法中有兩個對Observable的子類非常重要:一個是setChanged(),另一個是notifyObservers()。第一方法setChanged()被調(diào)用之后會設(shè)置一個內(nèi)部標(biāo)記變量,代表被觀察者對象的狀態(tài)發(fā)生了變化。第二個是notifyObservers(),這個方法被調(diào)用時,會調(diào)用所有登記過的觀察者對象的update()方法,使這些觀察者對象可以更新自己。

package com.zyh.designpatterns.observerpattern3;

import java.util.Observable;
import java.util.Observer;

public class ProgramMonkeyObserver implements Observer{

    public ProgramMonkeyObserver(Observable obs)
    {
        obs.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("Programer look the SDK download process is: "+((SDKDownloadObservable)o).getState());
    }
}
package com.zyh.designpatterns.observerpattern3;

import java.util.Observable;

public class SDKDownloadObservable extends Observable{

    private String mState;

    public String getState()
    {
        return mState;
    }

    public void netProcessChange(String data)
    {
       mState = data;
       this.setChanged();
       this.notifyObservers();
    }
}
package com.zyh.designpatterns.observerpattern3;

public class Main {

    public static void main(String[] args)
    {
       SDKDownloadObservable sdkDownloadObservable = new SDKDownloadObservable();
       new ProgramMonkeyObserver(sdkDownloadObservable);

       sdkDownloadObservable.netProcessChange("1%");
       sdkDownloadObservable.netProcessChange("51%");
       sdkDownloadObservable.netProcessChange("100%");
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容