用途:定義對象之間的一對多依賴關係,因此,當一個對象的狀態發生改變時,其所有依賴項都會得到通知,並自動更新。
它是 OO 設計模式的皇后。該模式被人們廣泛應用(特別是在 GUI 應用程序中),並構成了 MVC 架構的關鍵部分。它處理複雜的問題,而在解決這類問題方面表現得相對較好。但是,從實現需要的努力和代碼理解的角度來說,它還是帶來了一些難以解決的難題。
不足:觀察者(Observer)模式要求您先侵入系統中現有的類,然後才能支持該模式 —— 至少在 Java 語言中是這樣。
而方面可以降低像觀察者(Observer)模式這種侵入性模式的負擔,使得模式參與者更靈活,因爲不需要包含模式代碼。而且,模式本身可以變成抽象的基本方面,允許開發人員通過導入和應用它來實現重用,不必每次都要重新考慮模式。
下面通過一個例子來說明:
假設如下的情況:
AccountManager 對象能夠觀察 Account,這樣,在帳戶狀態改變時,它們可以向銷售人員發送一封電子郵件。
代碼如下:
public class Account {
private int state;
private String name;
public String getName() {
return name;
}
public Account(String name) {
super();
this.name = name;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
@Override
public String toString() {
return name;
}
}
public class AccountManager {
public void sendEmail(Account account) {
System.out.println("send Email:" + account);
}
}
Java 語言的觀察者
雖然實現的差異很明顯,但在它們之間還是有一些相似之處。不論如何實現觀察者,代碼中都必須回答以下 4 個問題:
1. 哪個對象是主體,哪個對象是觀察者?
2. 什麼時候主體應當向它的觀察者發送通知?
3. 當接收到通知時,觀察者應該做什麼?
4. 觀察關係應當在什麼時候開始,什麼時候終止?
角色定義
首先從標記器接口來分配角色開始。Observer 接口只定義了一個方法:update(),它對應着 Subject 發送通知時執行的操作。 Subject 承擔着更多的職責。它的標記器接口定義了兩個方法,一個用來跟蹤觀察者,另一個用來通知事件的那些觀察者。
public interface Observer {
public void update(Subject subject);
}
public interface Subject {
public void addObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObservers();
}
一旦定義了這些角色,就可以把它們應用到系統中對應的角色上。
應用觀察者角色
public class AccountManager implements Observer {
public void update(Subject subject) {
sendEmail((Account) subject);
}
}
一旦這項工作完成,就可以轉移到Subject。在這裏,要對 Account進行修改:
private Set observers = new HashSet();
public void addObserver(Observer o) {
observers.add(o);
}
public void removeObserver(Observer o) {
observers.remove(o);
}
public void notifyObservers() {
for (Observer o : observers) {
o.update(this);
}
}
觸發事件
現在已經把類調整到它們在模式中的角色上了。但是,還需要回過頭來,在對應的事件發生時觸發通知。
public void setState(int state) {
if (this.state != state) {
this.state = state;
notifyObservers();
}
}
啓動觀察關係
public static void main(String[] args) {
AccountManager manager = new AccountManager();
AccountManager manager2 = new AccountManager();
Account account = new Account("Account1");
account.addObserver(manager);
account.addObserver(manager2);
account.setState(1);
}
}
AspectJ 觀察者
定義抽象類來實現觀察者
public abstract class AbstractSubjectObserver<Sub, Obv> {
//不允許空item
protected static void iaxIfNull(Object item, String name) {
if (null == item) {
throw new IllegalArgumentException("null " + name);
}
}
//用於保存所有的主體和觀察者之間的對象關係
private final HashMap<Sub, ArrayList<Obv>> fObservers = new HashMap<Sub, ArrayList<Obv>>();
protected AbstractSubjectObserver() {
}
public synchronized void addObserver(Sub subject, Obv observer) {
iaxIfNull(subject, "subject");
iaxIfNull(observer, "observer");
getObservers(subject).add(observer);
}
public synchronized void removeObserver(
Sub subject,
Obv observer) {
iaxIfNull(subject, "subject");
iaxIfNull(observer, "observer");
getObservers(subject).remove(observer);
}
public synchronized ArrayList<Obv> getObservers(Sub subject) {
iaxIfNull(subject, "subject");
ArrayList<Observer> result = fObservers.get(subject);
if (null == result) {
result = new ArrayList<Observer>();
fObservers.put(subject, result);
}
return result;
}
//主體狀態改變,更新所有的觀察者對象
protected void subjectChanged(Sub subject) {
iaxIfNull(subject, "subject");
ArrayList<Observer> list = getObservers(subject);
if (!list.isEmpty()) {
updateObservers(subject, Collections.unmodifiableList(list));
}
}
//更新所有觀察者操作,調用具體的updateObserver
protected synchronized void updateObservers(
Subject subject,
List<Observer> observers) {
iaxIfNull(subject, "subject");
iaxIfNull(observers, "observers");
for (Observer observer : observers) {
updateObserver(subject, observer);
}
}
//需要子類實現,具體的更新操作
protected abstract void updateObserver(Subject subject, Observer observer);
}
定義方面:
AbstractSubjectObserver<Sub, Obv> {
//需要橫切的代碼,表示哪些需要觸發觀察者模式
protected abstract pointcut changing();
//在狀態改變後,觸發所有的觀察者
after(Sub subject) returning : target(subject) && changing() {
subjectChanged(subject);
}
}
無需改動原有的實現,看一下客戶端如何啓動觀察關係
public static void main(String[] args) {
Account account=new Account("Account1");
Client client=Client.aspectOf();
client.addObserver(account,new AccountManager());
client.addObserver(account,new AccountManager());
account.setState(1);
}
static aspect Client extends SubjectObserver<Account, AccountManager> {
protected pointcut changing() : execution(void Account.setState(int));
protected void updateObserver(Account account, AccountManager manager) {
manager.sendEmail(account);
}
}
}
AspectJ 觀察者的分析
易於理解:從參與者的視角來看,AOP 版本的觀察者更簡單
重用:可以很容易的實現重用