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

设计模式 —– 观察者模式

个人博客,想要搭建个人博客的可以进来看看: 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;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值