觀察者模式,以前看過,今天想了一下,似乎有點模糊了,回顧一下,再加之以筆記,以備……
行為模式,為實現此模式,應該具備這幾個角色:被觀察的主題,觀察者。這是必須的!一般來說,為使構建的東西有一定的可用性,會進行進一步的分工。主題角色再分為抽象主題和具體主題,同樣滴劃分觀察者角色為抽象觀察者及具體觀察者角色。這就是將在此文中提及的 Subject, ConcreteSubject, Observer, ConcreteObserver。
按照《JAVA 與模式》書來的,實現了最簡單的兩個版本。
版本一:
/** 抽象主題角色,屬於被觀察者 */
public interface Subject {
/**
* 登記一個新的觀察者對象
*/
public void attach(Observer observer);
/**
* 刪除一個觀察者對象
*/
public void detach(Observer observer);
/**
* 通知所有登記過的觀察者對象
*/
void notifyObservers();
}
/** 具體主題角色,屬於被觀察者 */
public class ConcreteSubject implements Subject {
private Vector observersVector = new Vector();
/** 這裡省略了幾個方法的實現,無非是往向量中添加 Observer, 沒什麼好寫的 */
/**
* 通知所有登記過的觀察者對象
* 這裡和書有一點點的不一樣,我用的是 Iterator 接口來實現
* 書上的是 Enumeration ,但大同小異。
*/
public void notifyObservers() {
Iterator it = observersVector.iterator();
while(it.hasNext()) {
((Observer)it.next()).update();
}
}
}
/** 抽象觀察者角色 */
public interface Observer {
/**
* 調用這個方法會更新自己
*/
void update();
}
/** 具體觀察者角色 */
public class ConcreteObserver implements Observer {
/**
* 調用這個方法會更新自己
*/
public void update() {
System.out.println(this + " I am notified");
}
}
客戶端的 main() 如下:
public static void main(String[] args) {
Subject subject = new ConcreteSubject();
Observer observer1 = new ConcreteObserver();
Observer observer2 = new ConcreteObserver();
subject.attach(observer1);
subject.attach(observer2);
subject.notifyObservers();
}
版本一的實現基本上與書上的沒有什麼不同,而版本二則有一點點的不一樣。版本二只改變了版本一中的兩個被觀察者的一些細節。在此貼上:
/**
* 這是一個重量級的抽象主題角色,將子類的一些方法移至此
* 增加了抽象類的重量而減少了具體主題類的分量
*/
public abstract class Subject {
/**
* 保存所有對觀察者對象的引用
*/
private Vector observersVector = new Vector();
/**
* 更改主題的狀態
* 在書上沒有該方法,為了在客戶端能夠用基類聲明對象,將該方法的聲明移至此
*/
public abstract void change(String newState);
/** 在這裡也把往主題角色中添加/刪除觀察者對象的方法省略了 */
/**
* 通知所有登記過的觀察者對象
*/
public void notifyObservers() {
Iterator it = observersVector.iterator();
while(it.hasNext()) {
((Observer)it.next()).update();
}
}
}
/**
* 輕量級的具體主題類角色
*/
public class ConcreteSubject extends Subject {
private String state;
/**
* 更改主題的狀態
*/
public void change(String newState) {
state = newState;
this.notifyObservers();
}
}
客戶端的代碼是完全一樣的。
其實這樣一個模式是相對比較簡單的,當然,簡單並不意味著力量不大,呵呵。用另外一個形式來表示:
public class 被觀察者 {public void 通知觀察者() {觀察者對象.有情況發生();}}
public class 觀察者 {public void 有情況發生() {/* 在這裡做你想做的事情 *