no_mkd
一。什麼是觀察者模式?
把現實世界中的報紙與訂閱者的關係抽象出來就是觀察者模式,一種報紙對應多個訂閱者,訂閱者可以隨時解除訂閱,未訂閱的讀者也可以隨時開始訂閱。一旦有新報紙發布,所有的訂閱者都會收到新內容。
在觀察者模式中,報紙叫做主題 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 所关注的 Subject
public 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;
}
@Override
public 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(); //创建玩家 ABC Observer 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("答题活动结束。。"); } }
結果示例:

四。總結
從上面的例子可以看出觀察者模式的特點:
- 利用觀察者模式可以輕易地建立對象之間“一對多”的依賴關係;
- 利用觀察者模式的機制可以很容易的實現這種依賴關係的動態維護
暫無評論,快來發表你的看法吧