01_观察者设计模式

一、代码实例

仓库地址

https://github.com/dianjiu/design-pattern

https://gitee.com/dianjiu/design-pattern

二、什么是观察者模式?

观察者模式:定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生变化时,会通知所有观察者自动更新状态。Java已经提供了对观察者Observer模式的默认实现, Java对观察者模式的支持主要体现在Observable类和Observer接口。

三、模式理解

当一个对象改变需要同时改变其他对象,而且他不知道具体有多少对象需要改变的时候,考虑使用观察者模式。

四、应用场景

天气变化

超市活动价

黄金价波动

五、代码实现(以黄金价格变化为例)

5.1黄金总店(主题对象)

package co.dianjiu.learn.behavior.observer.jdk8;

import java.util.Observable;

/**
 * 黄金连锁总店
 *
 * 主题对象
 *
 * 继承Observable类
 */
public class GoldHeadObservable extends Observable {
    //产品名称
    private String productName;
    //产品价格
    private Double productPrice;

    public GoldHeadObservable() {
    }

    public GoldHeadObservable(String productName, Double productPrice) {
        this.productName = productName;
        this.productPrice = productPrice;
    }

    public String getProductName() {
        return productName;
    }

    public Double getProductPrice() {
        return productPrice;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public void setProductPrice(Double productPrice) {
        this.productPrice = productPrice;
        //设置产品价格的状态已经被改变
        this.setChanged();
        //通知所有分店
        this.notifyObservers(productPrice);
    }
}

5.2黄金分店(观察者对象)

package co.dianjiu.learn.behavior.observer.jdk8;

import java.util.Observable;
import java.util.Observer;

/**
 * 黄金连锁各分店
 *
 * 观察者
 *
 * 实现Observer接口
 */
public class GoldBranchObserver implements Observer {
    private String name;

    public GoldBranchObserver() {
    }

    public GoldBranchObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof GoldHeadObservable && arg instanceof Double) {
            GoldHeadObservable goldHeadObservable = (GoldHeadObservable) o;
            Double price = (Double) arg;
            System.out.println("您好:" + this.name + " ," + goldHeadObservable.getProductName()
                    + "的价格已经发生改变,现在的价格为:" + price + "元/克");
        }
    }
}


5.3测试实例


package co.dianjiu.learn.behavior.observer.jdk8;

public class Test {
    public static void main(String[] args) {
        //初始化黄金连锁店 黄金产品的价格为480元每克
        GoldHeadObservable goldHeadObservable = new GoldHeadObservable("黄金", 480.00);
        //创建 N 个分店,并把分店添加为观察者
        GoldBranchObserver jiujiang = new GoldBranchObserver("九江分店");
        GoldBranchObserver fuyang = new GoldBranchObserver("阜阳分店");
        goldHeadObservable.addObserver(jiujiang);
        goldHeadObservable.addObserver(fuyang);
        //黄金价格波动后的价格为420元每克
        goldHeadObservable.setProductPrice(420.00);

    }
}

5.4测试截图

在这里插入图片描述

六、Observer和Observable废弃

6.1废弃原因

Observer和Observable在Java 9标记为废弃有几个原因:

不能序列化

Observable没有实现Serializable接口,它的内部成员变量都是私有的,子类不能通过继承它来对Observable的成员变量处理。所以子类也不能序列化。

不是线程安全

在 java.util.Observable文档里没有强制要求Observable是线程安全的,它允许子类覆盖重写Observable的方法,事件通知无序以及事件通知发生在不同的线程里,这些都是会影响线程安全的问题。

支持事件模型的功能简单

支持事件模型的功能很简单,例如,只是支持事情发生变化的概念,但是不能提供更多哪些内容发生了改变。

6.2解决方案

可以使用java.beans 里的PropertyChangeEventPropertyChangeListener 来代替目前Observer和Observable的功能。

七、JDK9+的观察者模式使用

7.1黄金总店

package co.dianjiu.learn.behavior.observer.jdk9;

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

/**
 * 黄金连锁总店
 *
 * 主题对象
 *
 * 依赖属性PropertyChangeSupport
 */
public class GoldHeadObservable {
    //产品名称
    private String productName;
    //产品价格
    private Double productPrice;

    private PropertyChangeSupport listeners = new PropertyChangeSupport(this);

    public GoldHeadObservable() {
    }

    public GoldHeadObservable(String productName, Double productPrice) {
        this.productName = productName;
        this.productPrice = productPrice;
    }

    public String getProductName() {
        return productName;
    }

    public Double getProductPrice() {
        return productPrice;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public void setProductPrice(Double productPrice) {
        String oldValue = String.valueOf(this.productPrice);
        this.productPrice = productPrice;
        String newValue = String.valueOf(productPrice);
        //发布监听事件
        firePropertyChange("productPrice",oldValue,newValue);
    }

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

    public void removePropertyChangeListener(PropertyChangeListener listener){
        listeners.removePropertyChangeListener(listener);
    }

    protected void firePropertyChange(String prop, Object oldValue, Object newValue) {
        listeners.firePropertyChange(prop, oldValue, newValue);
    }
}

7.2黄金分店

package co.dianjiu.learn.behavior.observer.jdk9;

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

/**
 * 黄金连锁各分店
 *
 * 观察者
 *
 * 实现PropertyChangeListener接口
 */
public class GoldBranchObserver implements PropertyChangeListener {
    private String name;

    public GoldBranchObserver() {
    }

    public GoldBranchObserver(String name) {
        this.name = name;
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        String propertyName = evt.getPropertyName();
        String oldPrice = (String) evt.getOldValue();
        String newPrice = (String) evt.getNewValue();
        System.out.println("您好:" + this.name + " ," + propertyName
                + "的价格已经发生改变,原来的价格为:"+oldPrice+"元/克,现在的价格为:" + newPrice + "元/克");
    }
}

7.3测试实例

package co.dianjiu.learn.behavior.observer.jdk9;

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

public class Test {
    public static void main(String[] args) {
        //初始化黄金连锁店 黄金产品的价格为480元每克
        GoldHeadObservable goldHeadObservable = new GoldHeadObservable("黄金", 480.00);
        //创建 N 个分店,并把分店添加为观察者
        GoldBranchObserver jiujiang = new GoldBranchObserver("九江分店");
        GoldBranchObserver fuyang = new GoldBranchObserver("阜阳分店");
        goldHeadObservable.addPropertyChangeListener(jiujiang);
        goldHeadObservable.addPropertyChangeListener(fuyang);
        //黄金价格波动后的价格为420元每克
        goldHeadObservable.setProductPrice(420.00);

        System.out.println("--------------------------------------------------");
        //测试移除一个监听者后,再调价格
        goldHeadObservable.removePropertyChangeListener(fuyang);
        goldHeadObservable.setProductPrice(430.00);
    }
}

7.4测试截图

在这里插入图片描述

八、学习小结

在通知所有观察者之前一定要调用 setChanged()方法来设置被观察者的状态已经被改变,这样notifyObservers()才会回调Observer的update方法进行更新。在JDK9开始Observer和Observable标记为废弃,由java.beans 里的PropertyChangeListener 和 PropertyChangeEvent 来代替,在主题对象中引入

private PropertyChangeSupport listeners = new PropertyChangeSupport(this);

监听对象,通过

listeners.firePropertyChange(prop, oldValue, newValue);

监听属性的变化。

同时可以通过

//添加观察者对象
listeners.addPropertyChangeListener(listener);
//移除观察者对象
listeners.removePropertyChangeListener(listener);

进行属性变化的观察者的添加和移除。

在监听者一方通过实现PropertyChangeListener接口,并重写propertyChange方法。

在这里插入图片描述

posted @ 2021-05-12 14:53  点九先生  阅读(65)  评论(0编辑  收藏  举报