设计模式---观察者模式(Observer)和委托事件模型(DEM)
1 引言
观察者模式,又名发布订阅模式,是一个一对多的关系,当被观察者发生某种变化,对应其观察者做出相应的改变。比如说,某学校研究生实验室有2个学生,2个学生某个上午在实验室,A在玩游戏,B在看电影,但是害怕老板进屋把他们逮个正着,怎么办?这2个学生和楼下安保处的门卫关系都特别好,他们就和门卫说了,如果看到他们老板进楼,就赶紧通知他们一声,他们好转换进入学习模式。在这个例子中,门卫就是被观察者(可不是老板啊),也就是事件的发布者,2个学生就是观察者,只要在门卫那里登了记,门卫一群发消息,就能收到通知,做出改变。
2 观察者模式的优点
解耦。观察者模式所做的工作就是解除耦合,让观察者与被观察者都依赖于各自上层的抽象,而不是依赖于具体实现,从而使得观察者与被观察者的具体实现代码变化不会互相影响。
3 适用场景
当一个对象的改变需要引起其他对象的改变时,这里是指状态的变化,而不是指代码的变化。尤其是一个对象变化但却不知道会引起多少其他对象的变化。
4 观察者代码示例
4.1 抽象的被观察者
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 10:47* @description: 通知者的接口**/public interface Subject {/*** 添加观察者** @param observer 观察者*/void addObserver(Observer observer);/*** 删除观察者** @param observer 观察者*/void deleteObserver(Observer observer);/*** 通知观察者** @param msg 通知信息*/void notifyAll(String msg);
}
4.2 具体的观察者
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 11:02**/public class ConcreteSubject implements Subject{//确保观察者不会重复存在Set<Observer> observers = new HashSet<>();@Overridepublic void addObserver(Observer observer) {if (observer == null){throw new NullPointerException("观察者不允许为空");}observers.add(observer);}@Overridepublic void deleteObserver(Observer observer) {observers.remove(observer);}@Overridepublic void notifyAll(String msg) {for (Observer o: observers) {o.update(this, msg);}}
}
4.3 抽象的观察者
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 10:47* @description: 观察者的接口**/public interface Observer {/*** 接收到通知,更新自我的状态** @param subject 通知者* @param msg 通知信息*/void update(Subject subject, String msg);
}
4.4 具体观察者1-玩游戏
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 11:09**/public class GameObserver implements Observer{@Overridepublic void update(Subject subject, String msg) {System.out.println("这里是" + subject.getClass() + "," + msg + "请停止打游戏");}
}
4.5 具体观察者2-看电影
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 11:09**/public class MovieObserver implements Observer{@Overridepublic void update(Subject subject, String msg) {System.out.println("这里是" + subject.getClass() + "," + msg + "请停止看电影");}
}
4.6 主程序
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 11:18**/
public class MainClass {public static void main(String[] args) throws Exception {ConcreteSubject concreteSubject = new ConcreteSubject();GameObserver gameObserver = new GameObserver();MovieObserver movieObserver = new MovieObserver();concreteSubject.addObserver(gameObserver);concreteSubject.addObserver(movieObserver);concreteSubject.notifyAll("有内鬼");}
}
4.7 执行结果
5 观察者模式的不足
1.尽管观察者与被观察者都做了抽象,但是接口之间彼此还是有耦合;例如,我们在定义Subject的接口是,添加观察者与删除观察者还是耦合了观察者Observer接口。
2.被观察者发布的方法是固定不变的,玩游戏的同学收到通知想要做的是关闭游戏,然后在老师来之前开溜,看电影的同学想要在老师来之前关闭电影,打开idea刷个好印象,现在是不能实现的,被观察者统一调用update方法。
6 委托事件模型(DEM)
个人理解,委托,就是把以前自己需要做的事情,转给别人做。主题(Subject)角色负责发布事件,而观察者向特定的主题订阅它所感兴趣的事件,当一个具体主题产生一个事件时,他就会通知所有感兴趣的订阅者。而且能够动态的订阅和取消。DEM中发布者叫做事件源(event source),而订阅者叫做事件监听器(event listener)。
具体如何实现了?我们首先定义一个事件Event,Event的任务就是执行传入进来的对象的方法,这样,对象不同,方法可以不同,这就解决了缺点的第二个问题-观察者固定不变的方法。再定义一个EventHandler类,负责添加事件与发布事件,而Subject只需要传入EventHandler类,添加订阅的事件与发布消息,这样就解决了第一个关于耦合的问题。
7 委托事件代码实现
7.1 Event类
*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 14:14**/
@Data
@Setter
@Getter
public class Event {/*** 委托事件者*/private Object object;/*** 委托执行的方法*/private String methodName;/*** 委托执行的方法参数*/private Object[] params;/*** 执行方法的参数类型*/private Class[] paramTypes;public Event(){//无参构造}public Event(Object object, String methodName, Object...params){this.object = object;this.methodName = methodName;this.params = params;contractParamTypes(this.params);}/***构造参数类型数组**/private void contractParamTypes(Object[] params){this.paramTypes = new Class[params.length];for (int i = 0; i < params.length; i++) {this.paramTypes[i] = params[i].getClass();}}/***执行委托的方法**/public void invoke() throws Exception {Method method = object.getClass().getMethod(this.methodName, this.paramTypes);method.invoke(this.object, this.params);}}
7.2 EventHandler类
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 14:37**/
@Data
public class EventHandler {private Set<Event> events;public EventHandler(){this.events = new HashSet<>();}//相当于添加一个事件,关联一个观察者public void addEvent(Object object, String methodName, java.lang.Object[] args){events.add(new Event(object, methodName, args));}//发布事件public void subscribeNotice() throws Exception {for (Event e: events){e.invoke();}}
}
7.3 Source被观察者抽象接口
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 14:56**/
public interface Source {/*** 添加观察者** @param object 观察者实例* @param methodName 执行方法名称* @param args 方法的参数*/void addListener(Object object, String methodName, Object...args);/*** 通知* @throws Exception*/void subscribeNotice() throws Exception;
}
7.4 Source具体实现类ConcreteSource
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 14:59**/
public class ConcreteSource implements Source{private final EventHandler eventHandler = new EventHandler();@Overridepublic void addListener(Object object, String methodName, Object...args) {eventHandler.addEvent(object, methodName, args);}@Overridepublic void subscribeNotice() throws Exception {eventHandler.subscribeNotice();}
}
7.5 观察者1-看电视选手TvObserver
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 15:18**/
public class TvObserver {public void stopWatchTv(String reason){System.out.println("赶快别看电视了, " + reason);}
}
7.6 观察者2-摸鱼选手AttachFishObserver
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 15:18**/
public class AttachFishObserver {public void stopAttachFish(Date date) {SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println(f.format(date));System.out.println("赶快别看摸鱼了, 看看时间啊,我的哥");}
}
7.7 主函数
/*** @program: design-pattern-learning* @author: zgr* @create: 2021-08-31 11:18**/
public class MainClass {public static void main(String[] args) throws Exception {ConcreteSubject concreteSubject = new ConcreteSubject();GameObserver gameObserver = new GameObserver();MovieObserver movieObserver = new MovieObserver();concreteSubject.addObserver(gameObserver);concreteSubject.addObserver(movieObserver);concreteSubject.notifyAll("有内鬼");System.out.println("---------------------分界线----------------------");ConcreteSource concreteSource = new ConcreteSource();TvObserver tvObserver = new TvObserver();AttachFishObserver attachFishObserver = new AttachFishObserver();concreteSource.addListener(tvObserver, "stopWatchTv", "你老妈回来了");concreteSource.addListener(attachFishObserver, "stopAttachFish", new Date());concreteSource.subscribeNotice();}
}
7.8 执行结果
8 总结
本文依据自己的理解,介绍了观察者模式,通过观察者模式的不足,引出委托事件,给出代码与执行结果。
9 引用
1.用java语言实现事件委托模式
2.观察者模式和事件委托
3.观察者设计模式 Vs 事件委托(java)
4.《大话设计模式》
10 源码
https://github.com/airhonor/design-pattern-learning
设计模式---观察者模式(Observer)和委托事件模型(DEM)相关推荐
- 设计模式-观察者模式(Observer)-Java
设计模式-观察者模式(Observer)-Java 目录 文章目录 1.前言 2.示例案例-多人联机对战游戏的设计 3.观察者模式概述 3.1.观察者模式定义 3.2.观察者模式结构 3.3.观察者模 ...
- java设计模式--观察者模式(Observer)
java设计模式--观察者模式(Observer) java设计模式--观察者模式(Observer) 观察者模式的定义: 定义对象间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖于它的 ...
- C++设计模式--观察者模式(Observer)
概述 观察者模式,定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新. 适用场景 以下任一情况下可以使用观察者模式: 当一个抽象模型有两方面,其中一 ...
- java委托事件模型_JAVA授权事件模型讲解(原创)
JAVA的授权事件模型包含三个概念:事件源,事件,事件监听器. 一,事件源:一个产生事件的对象.当这个对象的内部状态改变时,事件就会产生.一个事件源必须注册一个事件监听器已使监听器能够可以接受一个特定 ...
- 设计模式-观察者模式(Observer Pattern)
设计模式-观察者模式 观察者模式是使用频率最高的设计模式之一,它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应.在观察者模式中,发生改变的对象称为观 ...
- 设计模式 - 观察者模式(Observer Pattern) Java内置 用法
观察者模式(Observer Pattern) Java内置 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26601659 ...
- 趣谈设计模式 | 观察者模式(Observer) :消息的发布与订阅
文章目录 案例:文章推送 观察者模式 观察者模式的运作流程 观察者模式解决的问题 观察者模式大显身手 总结 要点 应用场景 生产者-消费者模型 VS 观察者模式 完整代码及文档 案例:文章推送 假设我 ...
- Android常见设计模式——观察者模式 (Observer Pattern)
文章目录 1. 前言 2. 观察者模式 2.1 源码 2.2 结构 3. Android中的观察者模式 1. 前言 观察者模式是在代码框架中使用比较高的一个设计模式,常常又叫做订阅/发布模式.而通过这 ...
- Java设计模式—观察者模式(Observer pattern)
故事: 小雪是一个非常漂亮的女孩,漂亮的女孩总是有很多的追求者,而且追求者的队伍在不断的变动,随时有人进入这个队伍,也有人退出.男孩们追求女孩时总是表现出120%的关心,当小雪私自游玩时总是不断收到追 ...
最新文章
- BugBash活动分享
- C 关于unsigned int compzero = ~0;与unsigned int compzero = 0xFFFF; 的区别!
- SQL SERVER-约束
- go mod tidy 报错:verifying ...: checksum mismatch
- iOS15适配本地通知功能
- Java题-古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子对数为多少?
- excel中以文本形式保存长数字
- 《2020年全球程序员收入报告》,看完报告我酸了!
- utools配置内网穿透
- yolo3.cfg相关配置
- android 百度导航 过路费,高德地图和百度地图规划路线不一样,且过路费也有差别如何选择?...
- 【自动化测试】Web自动化测试框架01
- 简单使用hbuildx把vue-cli项目打包,并使用electron转换成可执行的exe文件
- 【渝粤题库】广东开放大学 建筑制图 形成性考核
- 敲定了,冰河要搞大事情了!
- android 系统升级 方法,Android Recovery 升级方法
- 广西职业技术学院计算机专业分数线,广西职业技术学院
- 【网易公开日】《梦幻西游》手游服务器如何实现200万玩家同时在线?(技术篇)
- Packager is not running at localhost:19001
- 三相故障检测c语言,基于DSP的三相异步电动机故障在线监测的研究
热门文章
- 31年前的Beyond演唱会,是如何超清修复的?(推荐)
- 我的世界服务器唱片修改,我的世界怎么修改音乐 音乐资源包使用教程
- flink中的时间属性
- php access 教程 pdf,Access 2007 以PDF 格式保存文件
- thinkphp 文件上传为什么总是显示没有上传的文件解决方案
- Altera FPGA基本开发流程
- QWT坐标刻度设置时的2个细节
- 百度地图 多轨迹 示例
- 使用hive报 return code 2 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask解决方法
- PID算法控制的PWM调速