觀察者模式(也叫做發佈-訂閱;源-監聽器)
是什麼?
--觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同事監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知所有觀察着對象,使他們能夠自動更新自己。
解決什麼問題?
--在軟件系統中常常要求某一個對象的狀態發生變化時,某些其他的對象做出相應的改變。爲了在設計上達到低耦合與代碼的可複用性,那麼設計人員要使這些低耦合度的對象之間能夠維持行動的協調一致,保證高度的協作。觀察者模式是滿足要求的最重要模式之一。
觀察者模式的類型?
--觀察者模式按照觀察者對象的存儲地點,分爲兩種:第一種是觀察者對象存儲在實際主題中;第二種是觀察者對象存儲在抽象主題中。(說明:這裏所說的主題就是被觀察者對象)
針對第一種舉一個簡單的事例,代碼如下:
/**
* 抽象觀察者只定義了一個更新自身的方法
* @author Administrator
*
*/
public interface Observer {
public void update();
}
/**
* 具體觀察者A,當調用update方法時,會做出相應的更新
* @author Administrator
*
*/
public class ObserverA implements Observer{
private String name;
public ObserverA(String name){
this.name = name;
}
@Override
public void update() {
System.out.println(this.name+" updated ");
}
}
/**
* 抽象主題(抽象的被觀察者)
* 此對象不存儲觀察者,具體的存儲任務交給子類
* @author Administrator
*
*/
public interface Subject {
/**
* 給集合中添加一個觀察者
* @param observer
*/
public void attach(Observer observer);
/**
* 從集合中刪除一個觀察者
* @param observer
*/
public void detach(Observer observer);
/**
* 通知所有的觀察者更新自己
*/
public void notifyObservers();
}
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* 具體的主題(具體的被觀察者對象)
* 有存儲觀察者的集合(另一種觀察者模式類型正是把對觀察者對象存儲在移至抽象主題中)
* @author Administrator
*
*/
public class ConcreteSubject implements Subject{
private Set<Observer> observerlist = null;
public ConcreteSubject(){
if(this.observerlist == null){
this.observerlist = new HashSet<Observer>();
}
}
@Override
public void attach(Observer observer) {
if(!observerlist.contains(observer)){
observerlist.add(observer);
}
}
@Override
public void detach(Observer observer) {
observerlist.remove(observer);
}
@Override
public void notifyObservers() {
if(observerlist !=null && observerlist.size()>0){
Iterator<Observer> iter = observerlist.iterator();
while(iter.hasNext()){
Observer ob = iter.next();
ob.update();
}
}
}
}
/**
* 客戶端代碼
* @author Administrator
*
*/
public class Client {
public static void main(String[] args){
//定義三個觀察者和一個主題,把觀察者存儲在主題中
Observer ob1 = new ObserverA("xiao qiang");
Observer ob2 = new ObserverA("xiao ming");
Observer ob3 = new ObserverA("xiao jin");
Subject sub = new ConcreteSubject();
sub.attach(ob1);
sub.attach(ob2);
sub.attach(ob3);
//調用此方法,通知所有的觀察者,更新自己
sub.notifyObservers();
System.out.println("------------");
//刪除一個觀察者,然後再次通知所有的觀察者對象更新自身
sub.detach(ob1);
sub.notifyObservers();
}
}
觀察者模式的另一種實現方式是把存儲觀察者的任務從具體主題移到抽象主題角色中,之所以能夠這麼做,是因爲每一個具體主題角色都會定義一個存儲觀察者的集合,當主題角色的內部狀態發生變化時,可以更新到集合中所有的觀察者對象。既然所有的具體主題角色(抽象主題角色的子類)都會做這件同樣的事情,那麼我們就可以把它移到抽象主題角色中完成。此時的抽象主題角色需要用一個抽象類代替接口。
代碼如下:
抽象觀察者和具體觀察者對象都不變,代碼和上面的代碼相同
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* 抽象主題
* @author Administrator
*/
abstract public class Subject {
private Set<Observer> observerset = null;
/**
* 構造方法初始化集合
*/
public Subject(){
if(this.observerset == null){
this.observerset = new HashSet<Observer>();
}
}
/**
* 添加一個觀察者
* @param ob1
*/
public void attach(Observer ob1) {
if(!observerset.contains(ob1)){
observerset.add(ob1);
}
}
/**
* 刪除一個觀察者
* @param observer
*/
public void detach(Observer observer) {
observerset.remove(observer);
}
/**
* 通知所有的觀察者,更新自身
*/
public void notifyObservers() {
if(observerset !=null && observerset.size()>0){
Iterator<Observer> iter = observerset.iterator();
while(iter.hasNext()){
Observer ob = iter.next();
ob.update();
}
}
}
/**
* 返回一個遍歷集合的引用
* @return
*/
public Iterator<Observer> getObservers(){
Iterator<Observer> iter = null;
if(observerset !=null && observerset.size()>0){
iter = observerset.iterator();
}
return iter;
}
}
/**
* 具體主題角色,由於把觀察者集合的處理方法都移到抽象主題中,
* 所以具體的觀察者中的方法變得很簡單,可以專注於業務邏輯
* @author Administrator
*/
public class ConcerteSubject extends Subject {
//添加一個主題當前的狀態
private String state = "";
//改變主題狀態的同時通知所有的觀察者對象
public void change(String state){
this.state = state;
System.out.println("state changed ==>>>"+this.state);
this.notifyObservers();
}
}
/**
* 客戶端
* @author Administrator
*/
public class Client {
public static void main(String[] args){
//定義三個觀察者和一個主題,把觀察者存儲在主題中
Observer ob1 = new ObserverA("xiao qiang");
Observer ob2 = new ObserverA("xiao ming");
Observer ob3 = new ObserverA("xiao jin");
ConcerteSubject sub = new ConcerteSubject();
sub.attach(ob1);
sub.attach(ob2);
sub.attach(ob3);
//調用此方法,通知所有的觀察者,更新自己
sub.change("狀態A");
System.out.println("------------");
//刪除一個觀察者,然後再次通知所有的觀察者對象更新自身
sub.detach(ob1);
sub.change("狀態B");
}
}
java語言對於觀察者模式的支持
java語言的java.util庫裏面,提供了一個Observable類,以及一個Observer接口,構成java語言對於觀察者模式的支持。
Observer接口中只定義了一個方法,即update(Observable o,Observer agrs)方法。當被觀察者對象的狀態發生變化時,被觀察者對象的notifyObservers()方法就會調用觀察者對象的update(Observable o,Observer agrs)方法更新觀察者自身。
被觀察者類都是java.util.Observable類的子類。java.util.Observable提供公開的方法支持觀察者對象,這些方法中有兩個對Observer方法非常重要:一個是setChanged(),另一個是notifyObservers()。第一個方法setChanged()被調用的時候,會設置一個內部標記變量,代表被觀察者對象的狀態發生變化。第二個是notifyObservers()被調用的時候,會調用所有登記過的觀察者對象的update()方法,通知這些觀察者對象更新自己。除此之外,Observable對象還有添加觀察者對象addObserver(Observer
o),刪除觀察者對象deleteObserver(Observer o)等方法,如果讀者喜歡繼續研究,可以去查看對應的java.util.*包下對應的類。
本文僅僅是自己的學習筆記。如果有錯誤請指正,謝謝!