zoukankan      html  css  js  c++  java
  • 观察者模式

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

      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);
                                                        //回调应用层的实现
            }
        }
    }
  • 相关阅读:
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 梅花桩
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 元音字母辅音字母的数量
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 递增序列
    Java 第十一届 蓝桥杯 省模拟赛 最大的元素距离
  • 原文地址:https://www.cnblogs.com/klyjb/p/11540264.html
Copyright © 2011-2022 走看看