观察者模式

  观察者模式是非常常用的一种设计模式。在软件系统中,当一个对象的行为依赖与另一个对象的状态时,观察者模式就相当有用。若不实用观察者模式提供的通用结构,而需要实现其类似的功能,则只能在另一个线程中不停监听对象所依赖的状态。在一个复杂系统中,可能会因此开启很多线程来实现这一功能,这将使系统的性能产生额外的负担。观察者模式的意义也就在此,它可以在单线程中,使某一对象,及时得知自身所依赖的状态的变化。观察者模式的经典机构如图:

  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);
                                                    //回调应用层的实现
        }
    }
}

 

posted @ 2019-09-18 10:43  加了冰的才叫可乐  阅读(246)  评论(0编辑  收藏  举报