用AOP实现观察者模式

泡在网上的日子 / 文 发表于2012-10-29 22:28 次阅读

观察者(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 版本的观察者更简单
重用:可以很容易的实现重用

收藏 赞 (0) 踩 (0)
上一篇:Java观察者模式完整实现与剖析
观察者模式用途:定义对象之间的一对多依赖关系,因此,当一个对象的状态发生改变时,其所有依赖项都会得到通知,并自动更新。 它是 OO 设计模式的皇后。该模式被人们广泛应用(特别是在 GUI 应用程序中),并构成了 MVC 架构的关键部分。它处理复杂的问题,
下一篇:汉诺塔的递归算法与解析
汉诺塔的递归算法与解析 从左到右 A B C 柱 大盘子在下, 小盘子在上, 借助B柱将所有盘子从A柱移动到C柱, 期间只有一个原则: 大盘子只能在小盘子的下面. 如果有3个盘子, 大中小号, 越小的越在上面, 从上面给盘子按顺序编号 1(小),2(中),3(大), 后面的原理解析