觀察者模式也叫發(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%");
}
}