標籤:style blog http color os io java ar strong
一.什麼是觀察者模式?
把現實世界中的報紙與訂閱者的關係抽象出來就是觀察者模式,一種報紙對應多個訂閱者,訂閱者可以隨時解除訂閱,未訂閱的讀者也可以隨時開始訂閱。一旦有新報紙發布,所有的訂閱者都會收到新內容。
在觀察者模式中,報紙叫做主題Subject,訂閱者叫做觀察者Observer,一個Subject可以被多個Observer關注,Observer可以隨時解除關注,新的Observer也可以隨時關注Subject。Subject內容發生改變時,會通知所有的Observer。
二.舉個例子
很多網路遊戲中都有答題活動,所有參與答題活動的玩家都會同時收到題目資訊(延遲忽略不計),未參與活動的玩家可以中途加入,正在答題的玩家也可以隨時退出。
在此例中,遊戲伺服器就是“一”,玩家是“多”,題目資訊就是在它們之間傳遞的訊息。
怎樣才能設計出滿足以上要求的類?不妨試試觀察者模式。
首先,定義Subject抽象類別:
package ObserverPattern;import java.util.ArrayList;/** * @author ayqy * 定義Subject抽象類別 * */public abstract class Subject {ArrayList<Observer> observers = new ArrayList<Observer>();//觀察者列表/** * 註冊主題 * @param o 申請註冊該主題的Observer */public void registSubject(Observer o){observers.add(o);}/** * 刪除主題 * @param o */public void reomveSubject(Observer o){int index = observers.indexOf(o);observers.remove(index);}/** * 通知所有觀察者 * @param arg 該Subject想要傳遞給Observers的資料 */public void notifyObservers(Object arg){for(Observer o : observers)o.update(this, arg);}}
注意,這裡用了抽象類別而沒有用介面,為什嗎?
因為Subject的行為是fixed的,並不需要由子類來擴充。
-------
類似的,我們定義Observer抽象類別:
package ObserverPattern;/** * @author ayqy * 定義Observer抽象類別 * */public abstract class Observer {Subject subject = null;//定義該Observer所關注的Subjectpublic abstract void update(Subject subject, Object arg);//定義Observer的更新介面}
-------
下面開始實現我們的自訂Subject——GameServer:
package ObserverPattern;/** * @author ayqy * 定義GameServer類,繼承自Subject基類,負責發布題目 * */public class GameServer extends Subject{Question ques;//定義題目public Question getQues() {return ques;}public void setQues(Question q) {this.ques = q;super.notifyObservers(ques);//調用父類方法通知所有Observer}}
P.S.GameServer類的成員變數Question是對題目資訊的簡單封裝,Question類包含題號no與題目內容content兩部分定義,以及一個toString方法,返回題目描述資訊
-------
再實現我們的自訂Observer——Player:
package ObserverPattern;/** * @author ayqy * 定義PlayerA,繼承自Observer基類,負責接收新題目 * */public class PlayerA extends Observer{public PlayerA(Subject sub){subject = sub;}@Overridepublic void update(Subject subject, Object arg) {Question q = (Question)arg;System.out.println("PlayerA received " + q.toString());}}
P.S.為了使類層次更加清晰,此處並沒有定義Player基類
很容易複製粘貼得到PlayerB與PlayerC,不再贅述
至此,我們的類比答題活動準備工作已經結束了,下面我們需要定義一個測試類別來展示觀察者模式的魅力。
三.效果樣本
定義如下Test類:
package ObserverPattern;/** * @author ayqy * 實現一個測試類別,類比網路遊戲答題活動(遊戲伺服器按時更新題目資訊並通知所有參與答題的玩家) * */public class Test {public static void main(String[] args){System.out.println("答題活動即將開始。。");//建立伺服器GameServer gs = new GameServer();//建立玩家ABCObserver playerA = new PlayerA(gs);Observer playerB = new PlayerB(gs);Observer playerC = new PlayerC(gs);//為AB註冊Subject,C對答題不感興趣,拒絕註冊gs.registSubject(playerA);gs.registSubject(playerB);System.out.println("玩家AB成功參與答題活動。。");System.out.println("答題活動正式開始。。");gs.setQues(new Question(1, "第一題"));gs.setQues(new Question(2, "第二題"));System.out.println("玩家A不想玩了,退出答題活動。。");gs.reomveSubject(playerA);gs.setQues(new Question(3, "第三題"));System.out.println("玩家C想中途加入活動");gs.registSubject(playerC);gs.setQues(new Question(4, "第四題"));System.out.println("答題活動結束。。");}}
結果樣本:
四.總結
從上面的例子可以看出觀察者模式的特點:
1.利用觀察者模式可以輕易地建立對象之間“一對多”的依賴關係
2.利用觀察者模式的機制可以很容易的實現這種依賴關係的動態維護
設計模式之觀察者模式(Observer Pattern)