设计模式——观察者模式
观察者模式:对象之间多对一依赖的一种设计方案,
发布日期:2021-06-29 20:01:47
浏览次数:2
分类:技术文章
本文共 7821 字,大约阅读时间需要 26 分钟。
观察者模式
这篇博文是根据B站尚硅谷设计模式课程韩老师所讲而做的,在此表示感谢!
文章目录
被依赖的对象为 Subject
, 依赖的对象为 Observer
, Subject通知 Observer 变化,比如奶站\气象局\报社等就类似于 Subject,Subject是 1 的一方,Observer是用户是多的一方; 基本介绍:
- 观察者模式类似 订奶\订报\天气平台等业务
- Subject:主要是登记注册、移除和通知
Observer(观察者)
,主要有如下方法:- registerObserver() 注册观察者
- removeObserver() 移除观察者
- notifyObservers() 通知所有的注册的用户,根据不同需求,可以是更新数据,让用户来取,也可能是实施推送, 看具体需求定;
- Observer:观察者,主要接收Subject的通知;
案例介绍
我们通过如下一个案例来演示观察者模式,问题如下:
- 气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方);
- 需要设计开放型 API,便于其他第三方也能接入气象站获取数据;
- 提供温度、气压和湿度的接口;
- 测量数据更新时,要能实时的通知给第三方;
UML
编码
编写观察者的接口类
观察者的接口类Observer
如下所示:
package edu.hebeu.observer.observer;/** * 观察者接口 * @author 13651 * */public interface Observer { void update(float temperature, float pressure, float humidity);}
编写管理观察者的接口
管理观察者的接口Subject
,包括了对观察者的注册,删除,通知等方法,如下
package edu.hebeu.observer.subject;import edu.hebeu.observer.observer.Observer;/** * * @author 13651 * */public interface Subject { /** * 注册观察者 * @param observer */ void registerObserver(String observerName, Observer observer); /** * 删除观察者 * @param observer */ void removeObserver(String observerName); /** * 通知所有的观察者 */ void notifyObservers();}
编写能够测量、修改天气数据的类
该类嗨需要实现Subect接口
,使该类能够获得其内部的特性,如,注册、删除、通知观察者,以保证在每次数据更新时数据能实时的发送至观察者,让观察者将最新的数据展示,代码如下:
package edu.hebeu.observer.subject;import java.util.HashMap;import java.util.Map;import java.util.Set;import edu.hebeu.observer.observer.Observer;public class WeatherData implements Subject{ // 温度,气压,湿度 private float temperatrue; private float pressure; private float humidity; /** * 观察者集合 */ private Mapobservers; public WeatherData() { observers = new HashMap<>(); } /** * 获取温度 * @return */ public float getTemperature() { return temperatrue; } /** * 获取气压 * @return */ public float getPressure() { return pressure; } /** * 获取湿度 * @return */ public float getHumidity() { return humidity; } /** * 当数据有更新时,调用的函数 * @param temperature * @param pressure * @param humidity */ public void setData(float temperature, float pressure, float humidity) { this.temperatrue = temperature; this.pressure = pressure; this.humidity = humidity; //调用 notifyObservers, 将最新的信息 推送给 接入方 所有的观察者 notifyObservers(); } @Override public void registerObserver(String observerName, Observer observer) { observers.put(observerName, observer); System.out.println("添加《" + observerName + "》观察者成功!"); } @Override public void removeObserver(String observerName) { if(observers.containsKey(observerName)) { observers.remove(observerName); System.out.println("删除《" + observerName + "》观察者成功!"); return; } System.err.println("未找到《" + observerName + "》观察者,删除失败!"); } @Override public void notifyObservers() { Set > observerSet = observers.entrySet(); for(Map.Entry observer : observerSet) { observer.getValue().update(this.temperatrue, this.pressure, this.humidity); } }}
编写"第三方的接口“
实际上就类似于MySQL、Oracle实现Java提供的数据库驱动一样,我们为了模拟需要提供如下的几个类:
BaiDu
package edu.hebeu.observer.observer;public class BaiDu implements Observer{ // 温度,气压,湿度 private float temperature; private float pressure; private float humidity; /** * 更新天气情况,是由 WeatherData的对象实例来调用,即使用推送模式 * @param temperature * @param pressure * @param humidity */ @Override public void update(float temperature, float pressure, float humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; display(); } /** * 显示数据 */ public void display() { System.out.println("========================百度天气========================="); System.out.println("***Today mTemperature: " + temperature + "***"); System.out.println("***Today mPressure: " + pressure + "***"); System.out.println("***Today mHumidity: " + humidity + "***"); }}
WangYi
package edu.hebeu.observer.observer;public class WangYi implements Observer{ // 温度,气压,湿度 private float temperature; private float pressure; private float humidity; /** * 更新天气情况,是由 WeatherData的对象实例来调用,即使用推送模式 * @param temperature * @param pressure * @param humidity */ @Override public void update(float temperature, float pressure, float humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; display(); } /** * 显示数据 */ public void display() { System.out.println("========================网易天气========================="); System.out.println("&&&Today mTemperature: " + temperature + "***"); System.out.println("***Today mPressure: " + pressure + "---"); System.out.println("^^^Today mHumidity: " + humidity + "***"); }}
XinLang
package edu.hebeu.observer.observer;public class XinLang implements Observer{ // 温度,气压,湿度 private float temperature; private float pressure; private float humidity; /** * 更新天气情况,是由 WeatherData的对象实例来调用,即使用推送模式 * @param temperature * @param pressure * @param humidity */ @Override public void update(float temperature, float pressure, float humidity) { this.temperature = temperature; this.pressure = pressure; this.humidity = humidity; display(); } /** * 显示数据 */ public void display() { System.out.println("========================新浪天气========================="); System.out.println("---Today mTemperature: " + temperature + "---"); System.out.println("***Today mPressure: " + pressure + "***"); System.out.println("+++Today mHumidity: " + humidity + "+++"); }}
可以发现我们需要什么订阅者,直接就实现Observer接口
就好了,非常方便;
编写测试类
编写上述代码的测试类Client
,如下所示:
package edu.hebeu.observer;import java.util.Scanner;import edu.hebeu.observer.observer.BaiDu;import edu.hebeu.observer.observer.WangYi;import edu.hebeu.observer.observer.XinLang;import edu.hebeu.observer.subject.WeatherData;public class Client { private static float TEMPERATURE, PRESSURE, HUMIDITY; // 声明保持温度、湿度、气压的静态变量 public static void main(String[] args) { WeatherData weatherData = new WeatherData(); // 注册初始的观察者 weatherData.registerObserver("百度天气", new BaiDu()); weatherData.registerObserver("新浪天气", new XinLang()); weatherData.registerObserver("网易天气", new WangYi()); // 更新信息 weatherData.setData(37f, 158.9f, 29f); Scanner scanner = new Scanner(System.in); while(true) { System.out.println();System.out.println();System.out.println(); System.out.println("\"u(update)\"更新数据"); System.out.println("\"a(add)\"添加观察者"); System.out.println("\"r(remove)\"删除观察者"); System.out.println("\"e(exit)\"退出程序"); System.out.print("请输入:");Character keyword = scanner.next().charAt(0); if(keyword.equals('u')) { System.out.print("温度:"); TEMPERATURE = scanner.nextFloat(); System.out.print("湿度:"); PRESSURE = scanner.nextFloat(); System.out.print("气压:"); HUMIDITY = scanner.nextFloat(); System.out.println("--------------------------------------------天气更新-------------------------------"); weatherData.setData(TEMPERATURE, PRESSURE, HUMIDITY); // 改变数据 } else if(keyword.equals('a')) { System.out.print("请输入添加的观察者名:"); String observerName = scanner.next(); if(observerName.equals("百度天气")) { weatherData.registerObserver(observerName, new BaiDu()); } else if(observerName.equals("新浪天气")) { weatherData.registerObserver(observerName, new XinLang()); } else if(observerName.equals("网易天气")) { weatherData.registerObserver(observerName, new WangYi()); } else { System.err.println("第三方库中未找到" + observerName + "接口,添加失败!"); } } else if(keyword.equals('r')) { System.out.print("请输入删除的观察者名:"); String observerName = scanner.next(); weatherData.removeObserver(observerName); } else if(keyword.equals('e')) { // 如果输入是 "exit" break; // 退出循环 } } if(scanner != null) { scanner.close(); } System.out.println("bye~~"); }}
测试
测试更新天气数据,就会自动的通知其他的观察者改变它们的数据,然后将最新的数据显示出来,如下所示:
也可以将某些注册的观察者删除,如下: 也可以添加观察者,但是要保证有”该观察者“,如下:转载地址:https://blog.csdn.net/m0_49039508/article/details/116732205 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
很好
[***.229.124.182]2024年04月12日 17时28分00秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
项目管理的47个流程
2019-04-30
一张图遍历中外历史事件、科学发明、哲学思想对照表
2019-04-30
C# 利用VS自带的WSDL工具生成WebService服务类
2019-04-30
Devops学习一
2019-04-30
电商数据化管理
2019-04-30
单点登录时序图
2019-04-30
产品经理工作流程
2019-04-30
智慧校园整体架构
2019-04-30
CI/CD学习一
2019-04-30
软件开发组长的职责
2019-04-30
系统分析师学习一
2019-04-30
多线程高并发学习一
2019-04-30
Scrum学习一
2019-04-30
产品经理素质能力模型
2019-04-30
Kubernetes知识图谱
2019-04-30
年终总结全攻略
2019-04-30
ppt效率提升工具&资源网站&广告行业相关推荐
2019-04-30
运维工作内容
2019-04-30
数据分析学习一
2019-04-30
系统架构图
2019-04-30