【設計模式】用AOP實現觀察者模式

 觀察者(Observer)模式
    用途:定義對象之間的一對多依賴關係,因此,當一個對象的狀態發生改變時,其所有依賴項都會得到通知,並自動更新。
    它是 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代碼是如何實現觀察者模式的

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);
    }
  }

觸發事件
    現在已經把類調整到它們在模式中的角色上了。但是,還需要回過頭來,在對應的事件發生時觸發通知。
    Account
    public void setState(int state) {
        if (this.state != state) {
            this.state = state;
            notifyObservers();
        }
    }

啓動觀察關係

public class ObserverClient {

    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 觀察者

定義抽象類來實現觀察者

//採用java5的泛型來定義觀察對象和主體
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);

}


定義方面:
public abstract aspect SubjectObserver<Sub, Obv> extends
        AbstractSubjectObserver<Sub, Obv> {

    //需要橫切的代碼,表示哪些需要觸發觀察者模式
    protected abstract pointcut changing();

    //在狀態改變後,觸發所有的觀察者
    after(Sub subject) returning : target(subject) && changing() {
        subjectChanged(subject);
    }
}

無需改動原有的實現,看一下客戶端如何啓動觀察關係
public class ObserverClient {

    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 版本的觀察者更簡單
   重用:可以很容易的實現重用
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章