Observer Pattern(观察者模式)

      以OO的角度看待这个世界,其由数不尽的对象构成,而对象之间(1:1,1:n,m:n)都会产生相应的影响。
      eg: 羊🐑吃了老师布置的作业将导致小明被老师揍,气象局的天气预报将影响受众们日常出行等

观察者模式—— 在对象之间创建一对多的关系,当一个对象发生数据域的改变时,将通知所有依赖于该对象的对象自动更新相应的数据域。(观察者模式又称发布-订阅模式、模型-视图模式是对象行为型模式)

例子

用户界面 --> 观察者(Observer)

业务数据 --> 被观察者(Subject\Observable)

用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。

面向对象设计的一个原则是: 系统中的每个类将重点放在某一个功能上,而不是其他方面,一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。

观察者设计模式定义了对象间一种 1:n的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。

使用场景

1. 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。这二者封装在独立的对象中,以使他们可以各自独立地改变和复用。
2. 当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要被改变。
3. 当一个对象必须通知其他对象,而它又不能假定其他对象是谁。不希望对象之间是紧耦合的

设计模式是从大型架构出发,便于开发和维护思想,强调取依附(提倡组合式编程即类与类之间关系不是通过继承实现而是在运行时通过组合调用实现)

模式结构(主要角色)

  1. 抽象(Subject):也称之为抽象类,提供了一个用于保存观察者对象的聚集类和CD观察者对象的方法,以及通知所有观察者的抽象方法。
  2. 具体主题(Concrete Subject):具体目标类,实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象
  3. 抽象观察者(Observer):一个抽象类或接口,包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
  4. 具体观察者(Concrete Observer):实现抽象观察者中定义的抽象方法,以便得到目标的更改通知时更新自身的状态。

模式实现

import java.util.ArrayList;
import java.util.List;

/**
 * 定义出版商(相当于主题)
 */
abstract class Publisher{
    // 信息
    public String info;
    // 订阅者列表
    public List<Subscriber> subscriberList;

    // 初始化列表
    public Publisher(){
        this.subscriberList = new ArrayList<Subscriber>();
    }
    // 更新信息
    public void updateInfo(String _info){
        this.info = _info;
        notifySubscriber(info);
    }

    // ========================================
    // 注册(订阅)
    public void registSubscriber(Subscriber subscriber){
        subscriberList.add(subscriber);
    }
    // 注销(推订)
    public void removeSubscriber(Subscriber subscriber){
        int index = this.subscriberList.indexOf(subscriber);
        this.subscriberList.remove(index);
    }
    // 通知(通知订阅者接收信息- 信息投送)
    protected abstract void notifySubscriber(String info);
}

class ChinaPublier extends Publisher{

    @Override
    protected void notifySubscriber(String info){
        for(Object object : this.subscriberList){
            ((Subscriber)object).accpet(info);
        }
    }
}

interface Subscriber{
    // 接收消息
    public abstract void accpet(String info);
}

class Subscriber01 implements Subscriber{

    @Override
    public void accpet(String info) {
        System.out.println("我是Subscriber01,我主动过来接收信息!");
        System.out.println("==================================");
        System.out.println("信息显示: " + info);
    }
}

public class DemoInObserverPattern {
    public static void main(String[] args) {
        // 出版商
        Publisher publisher = new ChinaPublier();
        // 订阅人01
        Subscriber subscriber = new Subscriber01();
        // 出版商添加订阅人
        publisher.registSubscriber(subscriber);
        // 投送信息
        publisher.updateInfo("China No.1");
        // 再次投送
        publisher.updateInfo("We are the world,OvO!");
    }
}

// 输出
我是Subscriber01,我主动过来接收信息!
==================================
信息显示: China No.1
我是Subscriber01,我主动过来接收信息!
==================================
信息显示: We are the world,OvO!

模式应用01

要建立一个系统三部分分比为气象站(获取实际气象数据的物理装置)、WeatherData对象(追踪来自气象站的数据,并更新布告板)和布告板(显示目前天气状况给用户看)

// 主题接口
interface Subject{
    // 注册
    public void registerObserver(Observer o);
    // 注销
    public void removeObserver(Observer o);
    // 通知 当主题状态改变时,调用notifyObservers()以通知所有的观察者
    public void notifyObservers();
}
// 观察者接口
interface Observer{
    // 主题会把状态值作为方法的参数传送给观察者
    public void update(float temp, float humidity, float pressure);
}

// 布告板显示接口
interface DisplayElement{
    public void display();
}

/**********************************************************************
 *                       接口具体实现                                   *
 **********************************************************************/

class WeatherData implements Subject{
    // 存放观察者的列表
    private List<Observer> observerList;
    // 主题自身数据域
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData(){
        this.observerList = new ArrayList<Observer>();
    }


    // 注册指定观察者
    @Override
    public void registerObserver(Observer o) {
        observerList.add(o);
    }

    // 注销指定观察者
    @Override
    public void removeObserver(Observer o) {
        int index = observerList.indexOf(o);
        if(index >= 0){
            observerList.remove(index);
        }
    }

    // 通知观察者进行相应数据更新
    @Override
    public void notifyObservers() {
        for(Object object : this.observerList){
            ((Observer)object).update(this.temperature,this.humidity,this.pressure);
        }
    }

    // 当气象站得到更新观测值后通知观察者
    public void measurementsChanged(){
        notifyObservers();
    }

    // 更新数据域
    public void setMeasurements(float _temperature, float _humidity, float _pressure){
        this.temperature = _temperature;
        this.humidity = _humidity;
        this.pressure = _pressure;
        measurementsChanged();
    }
}

class CurrentConditionsDisplay implements Observer, DisplayElement{
    private float temperature;
    private float humidity;
    private float pressure;
    private Subject weatherData;

    public CurrentConditionsDisplay(){
        this.weatherData = new WeatherData();
        weatherData.registerObserver(this); // 将当前观察者实现类进行注册
    }

    // 数据域更新
    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        display();
    }

    // 数据显示
    @Override
    public void display() {
        System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
    }
}


public class ObserverPatternDemo {
    public static void main(String[] args) {
        // 1. 创建主题实现对象
        WeatherData subject = new WeatherData();
        // 2. 创建观察者对象
        CurrentConditionsDisplay observer = new CurrentConditionsDisplay();
        // 3. 注册观察者
        subject.registerObserver(observer);
        // 4. 产生模拟数据同时将通知观察者对象进行相应数据域更新
        subject.setMeasurements(80, 65, 30.4f);
        // 再次更新
        System.out.println("===============数据更新===============");
        subject.setMeasurements(82, 70, 29.2f);
        // 再次更新
        System.out.println("===============数据更新===============");
        subject.setMeasurements(50, 50, 50.5f);
    }
}

/** 输出
 * Current conditions: 80.0F degrees and 65.0% humidity
 * ===============数据更新===============
 * Current conditions: 82.0F degrees and 70.0% humidity
 * ===============数据更新===============
 * Current conditions: 50.0F degrees and 50.0% humidity
 * */

参考:
HeadFirst设计模式
C语言中文网

posted @ 2020-08-18 22:54  Felix_Openmind  阅读(184)  评论(0)    收藏  举报
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}