设计模式 ----- 观察者模式

来源:互联网 发布:js下拉框默认选中 编辑:程序博客网 时间:2024/06/05 03:37

设计模式 —– 观察者模式

个人博客,想要搭建个人博客的可以进来看看: http://www.ioqian.top/


观察者模式,在对象之间定义一对多的依赖,当一个对象状态改变时,依赖他的对象就会收到通知。典型的实现是java swing中的组件监听事件,当我们点击按钮时会调用我们注册的回调函数;还有Rxjava等等

背景
我们是一个天气台,有许多客户,当我们天气信息更新时,我们需要通知用户进行刷新…,我们要利用的是观察者模式

此处输入图片的描述

观察者模式主要由下面几部分组成:

  • Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象
  • WeatherData :具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知
  • Observer:抽象观察者,是观察者者的抽象类,它是一个接口,里面有一个很重要的方法,当具体主题状态改变时,直接调用这个方法,这里实现了松耦合
  • BoardCallOne :具体观察者,是实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。

结合我们的背景和下面的代码,我们天气台就是一个具体主题,我们的客户就是具体观察者,我们这里抽象出了两个接口是为了实现松耦合

松耦合设计原则

当两个对象松耦合时,他们可以互相交互,但是不太清楚彼此之间的细节,我们这里让主题和观察者之间松耦合

我们怎么利用接口实现的松耦合哪?
- 关于观察者的一切,主题只知道观察者实现了Observer接口,主题不需要知道具体的观察者是谁,有什么细节,只要继承了Observer接口,有update()实现方法就可以
- 任何时候都可以增加新的观察者,因为主题仅仅依赖了Observer接口,我们可以随时增加或者删除观察者
- 有新的观察者时,主题的代码不要修改

此处输入图片的描述
抽象主题 Subject

public interface Subject {    //该方法把任意的观察者加入到观察者集合    public void registerObserver(Observer o);    //该方法把观察者从观察者从集合中除去,从此收不到状态改变    public void removeObserver(Observer o);    //当状态改变时通过观察者集合中的所以观察者    public void notifyAllObserver();}

抽象观察者 Observer

public interface Observer {    public void update(float temp,float humidity);}

具体主题 WeatherData

public class WeatherData implements Subject  {    //观察者集合    private List<Observer> observers;    //模拟自身状态,当这些状态改变时通知所有观察者    private float temperature;    private float humidity;    public WeatherData(){        observers = new ArrayList<>();    }    //模拟状态改变通知所有观察者    public void stateChanged(float temp , float humidity){        this.temperature = temp;        this.humidity = humidity;        notifyAllObserver();    }    //模拟状态改变通知所有观察者    public void stateChanged(){        notifyAllObserver();    }    @Override    public void registerObserver(Observer o) {        observers.add(o);    }    @Override    public void removeObserver(Observer o) {        int i = observers.indexOf(o);        if(i>=0){            observers.remove(i);        }    }    @Override    public void notifyAllObserver() {        for(Observer o : observers){            //这里很关键,这里调用的是抽象观察者的方法,不需要明白谁是观察者,只要继承了Observer的类就可以            o.update(temperature , humidity);        }    }}

具体观察者 BoardCallOne

public interface DisplayDevice {    public void display();}//继承DisplayDevice接口和观察者模式没什么联系public class BoardCallOne implements Observer ,DisplayDevice {    private static final String TAG = "BoardCallOne";    private float temp;    private float humidity;    //抽象主题主题    private Subject weatherData ;    public BoardCallOne(Subject weatherData) {        this.weatherData = weatherData;        //作为观察者,注册主题        weatherData.registerObserver(this);    }    //取消注册    public void removeRegister(){        weatherData.removeObserver(this);    }    //作为观察者必须实现的方法,所有当具体主题状态变化会通知我,我本身调用display()方法,实时刷新天气信息    @Override    public void update(float temp, float humidity) {        this.temp = temp;        this.humidity = humidity;        display();    }    @Override    public void display() {        System.out.println(TAG + " i get info from weather data {temp="+temp+",humidity="+humidity+"}");    }}

测试main

public class Main {    public static void main(String[] args) throws InterruptedException {        //具体主题实现这        WeatherData subject = new WeatherData();        //具体观察者,在观察者的构造方法中注册了主题        BoardCallOne boardCallOne = new BoardCallOne(subject);        //在线程中一直让主题去通知观察者10次,每次休息1s        Thread t = new Thread(new Runnable() {            @Override            public void run() {                for(int i = 0 ; i < 10 ;i++){                    try {                        subject.stateChanged(10.0f,18.0f);                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });        t.start();        //主线程休眠5s后观察者取消注册,所以结果是会打印5次消息通知        Thread.sleep(5000);        boardCallOne.removeRegister();        //等待子线程结束        t.join();    }}结果验证了我们的猜测BoardCallOne i get info from weather data {temp=10.0,humidity=18.0}BoardCallOne i get info from weather data {temp=10.0,humidity=18.0}BoardCallOne i get info from weather data {temp=10.0,humidity=18.0}BoardCallOne i get info from weather data {temp=10.0,humidity=18.0}BoardCallOne i get info from weather data {temp=10.0,humidity=18.0}Process finished with exit code 0

总结

1.我们这里的是push模式,push模式是主题状态改变去通知所有观察者;还有pull,观察者可以主动去获取主题的状态

2.观察者模式用到了那些设计原则
- 变化分离原则,在观察者模式中,会改变的是主题的状态,及观察者的类型和数目,我们可以改变改变依赖于主题的对象,不必改变主题
- 针对接口编程原则,主题和观察者都使用了接口。观察者利用主题的接口进行向主题注册(在代码具体观察者的构造函数中);主题利用接口通知观察者,实现了松偶尔
- 多用组合,少用继承 ,利用组合把众多观察者包含进主题,private List observers;

原创粉丝点击