观察者模式(发布-订阅模式)
观察者模式:当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
角色:subject(被观察者)、observer(观察者)、concreteObserver(具体观察者)
博文推荐
案例描述
1、双向数据绑定
那我们要怎么理解什么是观察者呢?
了解前端的朋友应该很熟悉双向数据绑定机制,这里就很好体现了观察者模式,通过数据的变化驱动视图。再具体一点就是看下图
数据只有一份,而产生的视图会有两份甚至多份,当数据发生改变时,与之绑定的视图也会随之改变。
这里的数据可以看成subject
(被观察者)、视图看作observer
(观察者)。
2、国家气象网
要是还不理解的话,再举个栗子,我们都知道像温度、降水量、湿度这种信息一般以国家天气气象网为主,像百度、新浪、搜狗这种网站它们收集天气这种信息一般采用的都是第三方接口,也就是国家气象网,就相当于他们订阅了天气这种信息。只要国家气象网的温度、降水量、湿度等天气信息发生了改变,那相应的网站平台气象信息也会随之改变,这里的国家气象网可以理解为subject
,而订阅了这类消息的百度、新浪、搜狗网站可以看成observer
。
UML类图关系
具体代码如下
以下以国家天气网为例
Subject
package com.lcq.pattern.observer;
/**
* @Author coder
* @Date 2023-04-02
* @Desc 被观察者
*/
public interface Subject {
/**
* 注册观察者(订阅)
*
* @param observer
*/
void registerObserver(Observer observer);
/**
* 移除观察者(解除订阅)
*
* @param observer
*/
void removeObServer(Observer observer);
/**
* 通知观察者(发布)
*/
void notifyObServer();
}
MeteorologicalNetwork(国家气象网)
package com.lcq.pattern.observer;
import java.util.ArrayList;
import java.util.List;
/**
* @Author coder
* @Date 2023-04-02
* @Desc 气象网
*/
public class MeteorologicalNetwork implements Subject {
private int temperature;//温度
private String precipitation;//降水量
private int humidity;//湿度
private List<Observer> observerList;
public MeteorologicalNetwork(int temperature, String precipitation, int humidity) {
this.precipitation = precipitation;
this.temperature = temperature;
this.humidity = humidity;
observerList = new ArrayList<>();
}
public void changeWeather(int temperature, String precipitation, int humidity) {
this.temperature = temperature;
this.precipitation = precipitation;
this.humidity = humidity;
notifyObServer();
}
@Override
public void registerObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObServer(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyObServer() {
for (Observer observer : observerList) {
observer.update(temperature, precipitation, humidity);
}
}
}
Observer
package com.lcq.pattern.observer;
/**
* @Author coder
* @Date 2023-04-02
* @Desc 观察者
*/
public interface Observer {
/**
* 更新天气
* @param temperature 温度
* @param precipitation 降水量
* @param humidity 湿度
*/
void update(int temperature,String precipitation,int humidity);
}
Sina(新浪)
package com.lcq.pattern.observer;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
/**
* @Author coder
* @Date 2023-04-02
* @Desc 新浪
*/
@Slf4j
@Data
public class Sina implements Observer{
@Override
public void update(int temperature, String precipitation, int humidity) {
log.debug("新浪网 ===> 温度 -> {}℃,降水量 -> {}mm,湿度 -> {}%",temperature,precipitation,humidity);
}
}
BaiDU(百度)
package com.lcq.pattern.observer;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
/**
* @Author coder
* @Date 2023-04-02
* @Desc 百度
*/
@Slf4j
@Data
public class BaiDu implements Observer{
@Override
public void update(int temperature, String precipitation, int humidity) {
log.debug("百度网 ===> 温度 -> {}℃,降水量 -> {}mm,湿度 -> {}%",temperature,precipitation,humidity);
}
}
SouGou(搜狗)
package com.lcq.pattern.observer;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
/**
* @Author coder
* @Date 2023-04-02
* @Desc 搜狗
*/
@Slf4j
@Data
public class SouGou implements Observer {
@Override
public void update(int temperature, String precipitation, int humidity) {
log.debug("搜狗网 ===> 温度 -> {}℃,降水量 -> {}mm,湿度 -> {}%",temperature,precipitation,humidity);
}
}
测试
package com.lcq.pattern.observer;
import lombok.extern.slf4j.Slf4j;
/**
* @Author coder
* @Date 2023-04-02
* @Desc
*/
@Slf4j
public class Client {
public static void main(String[] args) {
Sina sina = new Sina();//新浪网
BaiDu baiDu = new BaiDu();//百度网
SouGou souGou = new SouGou();//搜狗网
MeteorologicalNetwork mn = new MeteorologicalNetwork(27, "56", 87);
mn.registerObserver(sina);//新浪订阅
mn.registerObserver(baiDu);//百度订阅
mn.registerObserver(souGou);//搜狗订阅
mn.notifyObServer();//发布通知
log.debug("---------------------------------------update-------------------------------");
mn.changeWeather(15,"45",23);
mn.removeObServer(souGou);//搜狗解除订阅
log.debug("---------------------------------------update-------------------------------");
mn.changeWeather(23,"32",43);
}
}
运行结果
23:17:16.434 [main] - 新浪网 ===> 温度 -> 27℃,降水量 -> 56mm,湿度 -> 87%
23:17:16.440 [main] - 百度网 ===> 温度 -> 27℃,降水量 -> 56mm,湿度 -> 87%
23:17:16.440 [main] - 搜狗网 ===> 温度 -> 27℃,降水量 -> 56mm,湿度 -> 87%
23:17:16.440 [main] - ---------------------------------------update-------------------------------
23:17:16.440 [main] - 新浪网 ===> 温度 -> 15℃,降水量 -> 45mm,湿度 -> 23%
23:17:16.440 [main] - 百度网 ===> 温度 -> 15℃,降水量 -> 45mm,湿度 -> 23%
23:17:16.440 [main] - 搜狗网 ===> 温度 -> 15℃,降水量 -> 45mm,湿度 -> 23%
23:17:16.441 [main] - ---------------------------------------update-------------------------------
23:17:16.441 [main] - 新浪网 ===> 温度 -> 23℃,降水量 -> 32mm,湿度 -> 43%
23:17:16.441 [main] - 百度网 ===> 温度 -> 23℃,降水量 -> 32mm,湿度 -> 43%
从运行结果我们可以看到,一旦国家气象网的天气发生改变(发布通知),只要是订阅了该气象信息的网站,他们的天气信息也会一起同步,而只要观察者取消订阅,国家气象网也不会再同步信息给取消订阅者了