zoukankan      html  css  js  c++  java
  • Java设计模式--观察者模式到监听器

    观察者模式是对象的行为模式。又叫做发布-订阅模式、模型-视图模式、源-监听器模式。

    抽象主题角色:主题角色将所有对观察者对象的引用到保存在一个集合里,每个主题都可以拥有任意数量的观察者。抽象主题提供一个接口,可以增加或者删除观察者对象。主题角色又叫被观察者。

    具体主题角色:将有关状态存入具体观察者对象,在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色是抽象主题的一个具体子类实现。

    抽象观察者角色:为所有的具体观察者定义一个接口,在得到主题通知的时候更新自己。

    具体观察者角色:抽象观察者的具体子类实现。

    代码

    抽象主题

    package com.demo.exercise.observer;
    
    /**
     * 抽象主题
     */
    public interface Subject {
    
        void add(Observer observer);
    
        void del(Observer observer);
    
        void notifyObservers();
    
    }

    抽象观察者

    package com.demo.exercise.observer;
    
    /**
     * 抽象观察者
     */
    public interface Observer {
    
        void update();
    
    }

    具体观察者

    package com.demo.exercise.observer;
    
    /**
     * 具体观察者
     */
    public class ConcreteObserver implements Observer {
        @Override
        public void update() {
            System.out.println(this + ":接收到通知了...");
        }
    }

    具体主题

    package com.demo.exercise.observer;
    
    import java.util.Iterator;
    import java.util.Vector;
    
    /**
     * 具体主题
     */
    public class ConcreteSubject implements Subject {
    
        private Vector<Observer> observers = new Vector<>();
    
        @Override
        public void add(Observer observer) {
            observers.add(observer);
        }
    
        @Override
        public void del(Observer observer) {
            observers.remove(observer);
        }
    
        @Override
        public void notifyObservers() {
            System.out.println("通知所有观察者...");
            Iterator<Observer> iterator = observers.iterator();
            while (iterator.hasNext()){
                iterator.next().update();
            }
        }
    }

    运行

        public static void main(String[] args) {
            Observer a = new ConcreteObserver();
            Observer b = new ConcreteObserver();
            Subject subject = new ConcreteSubject();
            subject.add(a);
            subject.add(b);
            subject.notifyObservers();
        }

    输出

    优化方案

    上面的【抽象主题角色】,其中管理集合的方法,都是由子类来实现的,而实际情况则是这些管理集合的方法是所有实现子类共用的,所以可以把这些转移到抽象主题中去。

    抽象主题(这里还是用的interface,你也可以用abstract class)

    package com.demo.exercise.observer;
    
    import java.util.Iterator;
    import java.util.Vector;
    
    /**
     * 抽象主题
     */
    public interface Subject {
    
        Vector<Observer> observers = new Vector<>();
    
        default void add(Observer observer){
            observers.add(observer);
        }
    
        default void del(Observer observer){
            observers.remove(observer);
        }
    
        default void notifyObservers(){
            System.out.println("通知所有观察者...");
            Iterator<Observer> iterator = observers.iterator();
            while (iterator.hasNext()){
                iterator.next().update();
            }
        }
    
        /**
         * 子类需要自定义的方法
         * @param status
         */
        void change(String status);
    }

    具体子类

    package com.demo.exercise.observer;
    /**
     * 具体主题
     */
    public class ConcreteSubject implements Subject {
    
        private String status;
    
        /**
         * 主题状态改变,调用通知方法
         * @param status
         */
        public void change(String status){
            System.out.println(status);
            this.status = status;
            this.notifyObservers();
        }
    }

    运行

        public static void main(String[] args) {
            Observer a = new ConcreteObserver();
            Observer b = new ConcreteObserver();
            Subject subject = new ConcreteSubject();
            subject.add(a);
            subject.add(b);
            subject.change("主题状态改变");
        }

    输出

    引申

    那么这种设计模式用来解决什么问题呢?类似于下面这种代码,大家初学Java的时候肯定用过,点击按钮事件,只要点击按钮,就会自动执行相关方法。

    JButton button = new JButton();
    button.addActionListener((event) -> {
        // TODO
    });

    其中的原理也是观察者模式。下面我就来简单模拟一下

    抽象主题

    package com.demo.exercise.observer;
    
    import java.util.Iterator;
    import java.util.Vector;
    
    /**
     * 抽象主题
     */
    public abstract class Button {
    
        private Vector<ActionListener> observers = new Vector<>();
    
        void addActionListener(ActionListener observer){
            observers.add(observer);
        }
    
        void removeActionListener(ActionListener observer){
            observers.remove(observer);
        }
    
        void notifyObservers(){
            Iterator<ActionListener> iterator = observers.iterator();
            while (iterator.hasNext()){
                iterator.next().actionPerformed();
            }
        }
    }

    抽象观察者

    package com.demo.exercise.observer;
    
    /**
     * 抽象观察者
     */
    public interface ActionListener {
    
        void actionPerformed();
    
    }

    具体主题

    package com.demo.exercise.observer;
    
    /**
     * 具体主题
     */
    public class JButton extends Button {
    
        /**
         * 点击事件
         */
        public void click(){
            System.out.println("【假装产生了点击事件】");
            this.notifyObservers();
        }
    
    }

    运行

        public static void main(String[] args) {
            JButton button = new JButton();
            button.addActionListener(() -> {
                System.out.println("点击事件处理...");
            });
            button.addActionListener(() -> {
                System.out.println("另外一个点击事件处理...");
            });
            button.click();
        }

    输出

    Java对观察者模式的支持

    一个是被观察者:java.util.Observable

    一个是观察者:java.util.Observer

    Observer里面只有一个update方法。

    public interface Observer {
        /**
         * This method is called whenever the observed object is changed. An
         * application calls an <tt>Observable</tt> object's
         * <code>notifyObservers</code> method to have all the object's
         * observers notified of the change.
         *
         * @param   o     the observable object.
         * @param   arg   an argument passed to the <code>notifyObservers</code>
         *                 method.
         */
        void update(Observable o, Object arg);
    }

    当被观察者的状态发生改变,就会调用这一方法。

        public void notifyObservers(Object arg) {
            /*
             * a temporary array buffer, used as a snapshot of the state of
             * current Observers.
             */
            Object[] arrLocal;
    
            synchronized (this) {
                /* We don't want the Observer doing callbacks into
                 * arbitrary code while holding its own Monitor.
                 * The code where we extract each Observable from
                 * the Vector and store the state of the Observer
                 * needs synchronization, but notifying observers
                 * does not (should not).  The worst result of any
                 * potential race-condition here is that:
                 * 1) a newly-added Observer will miss a
                 *   notification in progress
                 * 2) a recently unregistered Observer will be
                 *   wrongly notified when it doesn't care
                 */
                if (!changed)
                    return;
                arrLocal = obs.toArray();
                clearChanged();
            }
    
            for (int i = arrLocal.length-1; i>=0; i--)
                ((Observer)arrLocal[i]).update(this, arg);
        }

    用法呢,我再给你示范一下。

    创建一个事件对象

    package com.demo.exercise.observer;
    
    /**
     * 事件对象
     */
    public class ClickEvent {
    
        private String source;
    
        public ClickEvent(String source) {
            this.source = source;
        }
    
        public String getSource() {
            return source;
        }
    
        public void setSource(String source) {
            this.source = source;
        }
    }
    package com.demo.exercise.observer;
    
    import java.util.Observable;
    import java.util.Observer;
    
    /**
     * 具体观察者
     */
    public class JJButton extends Observable {
    
        public void click(){
            // 事件对象
            ClickEvent clickEvent = new ClickEvent("点击事件");
            // changed 置为true,表示状态改变,才会通知所有观察者,与之对应的是clearChanged
            this.setChanged();
            // 通知所有观察者
            this.notifyObservers(clickEvent);
        }
    
        public void addListener(Observer o){
            this.addObserver(o);
        }
    
    }

    运行

        public static void main(String[] args) {
            JJButton button = new JJButton();
            button.addListener((o, arg) -> {
                ClickEvent event = (ClickEvent) arg;
                System.out.println("事件源:" + event.getSource());
            });
            button.click();
        }

    输出

  • 相关阅读:
    PythonのTkinter基本原理
    使用 Word (VBA) 分割长图到多页
    如何使用 Shebang Line (Python 虚拟环境)
    将常用的 VBScript 脚本放到任务栏 (Pin VBScript to Taskbar)
    关于 VBScript 中的 CreateObject
    Windows Scripting Host (WSH) 是什么?
    Component Object Model (COM) 是什么?
    IOS 打开中文 html 文件,显示乱码的问题
    科技发展时间线(Technology Timeline)
    列置换密码
  • 原文地址:https://www.cnblogs.com/LUA123/p/11412468.html
Copyright © 2011-2022 走看看