观察者模式II

发布时间 2023-10-14 12:43:03作者: haveanicedayfh

需求

以支付状态更新通知为例,当支付状态更新时,通知邮件服务和库存服务。

自定义观察者模式

package com.fh.observer;

import org.junit.Test;

import java.util.List;
import java.util.Vector;

/**
 * 推送模式
 */
public class ObserverTest6 {
    /**
     * 观察者
     */
    public interface Observer {
        void update();
    }

    /**
     * 库存服务
     */
    public class MyStockObserver implements Observer {
        @Override
        public void update() {
            System.out.println("库存服务收到通知");
        }
    }


    /**
     * 邮件服务
     */
    public class MyEmailObserver implements Observer {
        @Override
        public void update() {
            System.out.println("邮件服务收到通知.");
        }
    }

    /**
     * 被观察者
     */
    public interface Subject {
        // 添加观察者
        void addObserver(Observer observer);

        //删除观察者
        void removeObserver(Observer observer);

        //通知观察者
        void notifyObservers();
    }

    /**
     * 更改支付状态的被观察则
     */
    public class MyPaymentStatusUpdateSubject implements Subject {

        private List<Observer> observers = new Vector<>();

        @Override
        public void addObserver(Observer observer) {
            observers.add(observer);
        }

        @Override
        public void removeObserver(Observer observer) {
            observers.remove(observer);
        }

        @Override
        public void notifyObservers() {
            for (Observer observer : observers) {
                observer.update();
            }
        }

        public void updatePaymentStatus(int newStatus) {

            // 业务逻辑操作
            System.out.println("更新新的支付状态为:" + newStatus);

            // 通知观察者
            this.notifyObservers();
        }
    }

    @Test
    public void m() {

        // "支付状态更新"->看做一个事件,可以被监听的事件

        // 被观察者。即事件源
        MyPaymentStatusUpdateSubject myPaymentStatusUpdateSubject = new MyPaymentStatusUpdateSubject();

        // 观察者。即事件监听器
        MyEmailObserver myEmailObserver = new MyEmailObserver();
        MyStockObserver myStockObserver = new MyStockObserver();

        // 添加观察者。
        myPaymentStatusUpdateSubject.addObserver(myEmailObserver);
        myPaymentStatusUpdateSubject.addObserver(myStockObserver);

        // 发布事件。支付状态更新。
        myPaymentStatusUpdateSubject.updatePaymentStatus(2);
    }
}

jdk中的观察者模式

JDK已经帮我们实现了一个观察者模式,事件收集器采用Vector容器保存,操作事件收集器的方法都是线程安全的。

我们针对JDK给出的观察者模式的解决方案总结几点:
1、Observable实现了大部分的逻辑,没有很好地进行抽象,灵活性降低了
2、存在2个潜在的问题:一个刚刚加入的观察者错过了通知;一个刚刚删除的观察者被错误的通知
3、Observable实现的方法采用synchronized,操作同一个方法时串行,可能会存在效率问题

package com.fh.observer;

import org.junit.Test;

import java.util.*;

public class ObserverTest7 {

    /**
     * 邮件服务
     */
    public class EmailObserver implements Observer {
        @Override
        public void update(Observable o, Object arg) {
            System.out.println("邮件服务收到通知");
        }
    }

    /**
     * 库存服务
     */
    public class StockObserver implements Observer {
        @Override
        public void update(Observable o, Object arg) {
            System.out.println("库存服务收到通知");
        }
    }

    /**
     * 支付状态变更做为一个可观察者
     */
    public class PaymentStatusObservable extends Observable {

        public void updatePaymentStatus(int newStatus) {
            // 业务逻辑操作
            System.out.println("更新新的支付状态为:" + newStatus);

            // 通知观察者
            this.setChanged();//需要调用一下这这方法,表示被观察者的状态已发生变更,Observable才会通知观察者
            this.notifyObservers();
        }
    }

    //使用JDK中的观察者模式
    @Test
    public void m() {
        // "支付状态更新"->看做一个事件,可以被监听的事件

        // 被观察者。即事件源
        PaymentStatusObservable paymentStatusObservable = new PaymentStatusObservable();

        // 添加观察者
        paymentStatusObservable.addObserver(new EmailObserver());
        paymentStatusObservable.addObserver(new StockObserver());

        // 支付状态变更
        paymentStatusObservable.updatePaymentStatus(3);
    }
}

JavaBean中的事件驱动

原理解析
javabean规范中提供了一种监听属性变化的事件驱动模型。提供操作Javabean属性的类PropertyChangeSupport和PropertyEditorSupport。

从事件驱动模型的各个构建来分析,PropertyChangeSupport和PropertyEditorSupport都属于事件源,能够产生事件。如果以观察模式的角度来看,则是被观察者

事件监听器实现PropertyChangeListener接口,通过PropertyChangeSupport和PropertyEditorSupport添加到事件队列中。

一旦有Javabean属性发生变化通过调用PropertyChangeSupport#firePropertyChange()、PropertyEditorSupport#firePropertyChange()即可触发监听器处理事件。

package com.fh.observer;

import org.junit.Test;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyChangeEvent;

public class ObserverTest8 {


    /**
     *从事件驱动模型的各个构建来分析,PropertyChangeSupport和PropertyEditorSupport都属于事件源,能够产生事件。
     * 如果以观察模式的角度来看,则是被观察者
     */
    public class PaymentStatusUpdateBean {

        PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

        public void updateStatus(int newStatus) {
            // 模拟业务逻辑
            System.out.println("支付状态更新: " + newStatus);
            // 触发通知 一旦有Javabean属性发生变化通过调用PropertyChangeSupport#firePropertyChange()
            propertyChangeSupport.firePropertyChange("paymentStatuUpdate", 0, newStatus);
        }

        public void addPropertyChangeListener(PropertyChangeListener listener) {
            propertyChangeSupport.addPropertyChangeListener(listener);
        }

        public void removePropertyChangeListener(PropertyChangeListener listener) {
            propertyChangeSupport.addPropertyChangeListener(listener);
        }
    }


    /**
     * 支付状态变更的监听器
     *
     * 事件监听器实现PropertyChangeListener接口,
     * 通过PropertyChangeSupport和PropertyEditorSupport添加到事件队列中。
     */
    public class PaymentStatusUpdateListener implements PropertyChangeListener {
        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            System.out.printf("支付状态变更. eventName : %s, oldValue : %s, newValue : %s", evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
        }
    }

    //测试JDK提供的PropertyChangeEvent
    @Test
    public void m() {
        PaymentStatusUpdateBean paymentStatusUpdateBean = new PaymentStatusUpdateBean();

        // 添加监听器
        paymentStatusUpdateBean.addPropertyChangeListener(new PaymentStatusUpdateListener());

        // 更新支付状态
        paymentStatusUpdateBean.updateStatus(3);
    }

}

Spring事件驱动