观察者模式
观察者模式是非常常用的一种设计模式。在软件系统中,当一个对象的行为依赖与另一个对象的状态时,观察者模式就相当有用。若不实用观察者模式提供的通用结构,而需要实现其类似的功能,则只能在另一个线程中不停监听对象所依赖的状态。在一个复杂系统中,可能会因此开启很多线程来实现这一功能,这将使系统的性能产生额外的负担。观察者模式的意义也就在此,它可以在单线程中,使某一对象,及时得知自身所依赖的状态的变化。观察者模式的经典机构如图:
ISubject是被观察对象,它可以增加或者删除观察者。IOberver是观察者,它依赖于ISubject的状态变化。当ISubject状态发生改变时,会通过Inform()方法通知观察者。
观察者模式的主要角色如下表:
角色 | 作用 |
主题接口 | 指被观察的对象。当其状态发生改变或者某事件发生时,它会将这个变化通知观察者。它维护了观察者所需要依赖的状态 |
具体主题 | 具体主题实现了主题接口中的方法。如新增观察者、删除观察者和通知观察者。其内部维护一个观察者列表 |
观察者接口 | 观察者接口定义了观察者的基本方法。当依赖状态发生改变时,主题接口就会调用观察者的update()方法 |
具体观察者 | 实现了观察者接口的update(),具体处理了当被观察者状态改变或者某一事件发生时的业务逻辑 |
主题接口的实现如下:
public interface ISubject { void attach(IObserver observer); //添加观察者 void detach(IObserver observer); //删除观察者 void inform(); //通知观察者 }
观察者接口的实现如下:
public interface IObserver { void update(Event event); //更新观察者 }
一个具体的主题实现,注意,它维护了观察者队列,提供了增加和删除观察者的方法,并通过其inform()通知观察者。
public class ConcreteSubject implements ISubject { Vector<IObserver> observers = new Vector<IObserver>(); @Override public void attach(IObserver obserser) { observers.add(obserser); } @Override public void detach(IObserver obserser) { observers.removeElement(obserser); } @Override public void inform() { Event event = new Event(); for (IObserver ob : observers) { ob.update(event); } } }
一个具体的观察者实现如下,当其监听的状态发生改变时,update()方法就会被主题回调,进而可以在观察者内部进行业务逻辑的处理。
public class ConcreteObserver implements IObserver { @Override public void update(Event event) { System.out.println("observer receives information"); } }
观察者模式是如此常用,以至于JDK内部就已经为开发人员准备了一套观察者模式的实现。它位于java.util包中,包括java.util.Observable类和java.util.Observer接口,它们的关系如下图:
在java.util.Observable类中,已经实现了主要的功能,如增加观察者、删除观察者和通知观察者,开发人员可以直接通过继承Observable使用这些功能。java.util.Observer接口是观察者接口,它的update()方法会在java.util.Observable的notifyObservers()方法中被回调,以获得最新的状态变化。通常在观察者模式中Observer接口总是应用程序的核心扩展对象,具体的业务逻辑总是被封装在update()方法中。
在JDK中,观察者模式也得到了普遍的应用。一个最典型的应用比那时Swing框架的JButton实现,它的时间处理机制如下图所示:
JButton继承自AbstractButton,在AbstractButton中维护类一组监听器,它们就装扮着被观察者的角色。而AbstractButton本身就是被观察者对象。监听器ActionoListener并不是依靠循环监听去获得按钮何时被单击,而是当按钮被单击时,通过AbstractButton的fireActionPermed()方法回调ActionListener.actionPerformed()方法实现。基于这种结构,在应用程序开发时,只需要简单地实现ActionListener接口(也就是Observer),并将其添加到按钮(Subject角色)的观察者列表中,那么当单机事件发生,就可以自动促发监听器的业务处理函数。下面从观察者模式的角度,分析一段按钮单击处理的代码:
public static class BtnListener implements ActionListener { //这就是具体的观察者 @Override public void actionPerformed(ActionEvent e) { //在fireActionPerformed()中被回调 System.out.println("click"); //按钮单击时,由具体观察者处理业务 } } public static void main(String[] args) { JFrame p = new JFrame(); JButton btn = new JButton("Click ME"); //新建具体主题 btn.addActionListener(new BtnListener()); //在具体主题中,假如观察者 p.add(btn); p.pack(); p.setVisible(true); }
当按钮被单击时,通过被观察对象通知观察者,以下时AbstractButton中的一段事件处理代码,显示了被观察对象如何通知观察者:
protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listtenerList.getListenerList();//这里就是应用层 //实现的ActionListener ActionEvent e = null; for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i] == ActionListener.class) { if (e == null) { String actionCommand = event.getActionCommand(); if(actionCommand == null) { actionCommand = getActionCommand(): } e = new ActionEvent(AbstractButton.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); //构造事件参数 //告诉应用层是何种事件发生 } ((ActionListener) listeners[i+1]).actionPerformed(e); //回调应用层的实现 } } }