当前位置: 首页 > news >正文

设计模式-行为型模式-观察者模式

行为模式包含:观察者模式,模板方法模式,策略模式,职责链模式,状态模式,命令模式,中介者模式,迭代器模式,访问者模式,备忘录模式,解释器模式。

1.观察者模式的定义

        定义对象之间一对多依赖关系,这样当一个对象改变状态时,他的所有依赖项都会自动得到通知和更新;

1.1 观察者模式的优缺点

优点

  • 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系;
  • 被观察者发送通知,所有注册的观察者都会收到信息;

缺点

  • 如果观察者很多的话,所有的观察者收到被观察者发送的通知会耗时;
  • 如果被观察者有循环依赖的话,那么被观察者发送通知会使观察者循环调用,会导致系统崩溃;

1.2 观察者模式的使用场景

  • 当一个对象状态的改变需要改变其他对象时,如商品库存数量发生变化需要通知商品详情页、购物车等系统改变数量;
  • 发布订阅的场景,如微信公众号、微博、b站等,发布者发布内容,通知便会发送到关注者;
  • 需要创建一种链式触发机制时,如在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象,这样通过观察者模式能够很好的实现;
  • 需要建立基于事件触发的场景,如基于 Java UI 的编程,所有键盘和鼠标事件都由它的侦听器对象和指定函数处理。当用户单击鼠标时,订阅鼠标单击事件的函数将被调用,并将所有上下文数据作为方法参数传递给它;

2.观察者模式原理

  • 抽象被观察者(Subject):把所有观察者对象保存在一个集合里,每个被观察者都可以有任意数量的观察者,抽象被观察者提供一个接口,可以增加和删除观察者对象;
  • 具体被观察者(ConcreteSubject):将有关状态存入具体观察者对象,在具体被观察者的内部状态发生改变时,给所有注册过的观察者发送通知;
  • 抽象观察者(Observer):是观察者的抽象类,定义了一个更新接口,使得在得到被观察者更改通知时更新自己;
  • 具体观察者(ConcreteObserver):实现抽象观察者定义的更新接口,以便在得到被观察者更改通知时更新自身的状态,在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要与具体目标一致;

3.观察者模式的实现

【实例】

        实现一个买房摇号的程序,摇号结束,需要通过短信告知用户摇号结果,还需要向MQ中保存用户本次摇号的信息。

【代码】

        事件监听

/*** 事件监听接口**/
public interface EventListener {void doEvent(LotteryResult result);
}/*** 短信发送事件**/
public class MessageEventListener implements EventListener {@Overridepublic void doEvent(LotteryResult result) {System.out.println("发送短信通知用户ID为: " + result.getuId() +",您的摇号结果如下: " + result.getMsg());}
}/*** MQ消息发送事件**/
public class MQEventListener implements EventListener {@Overridepublic void doEvent(LotteryResult result) {System.out.println("记录用户摇号结果(MQ), 用户ID:" +  result.getuId() +",摇号结果:" + result.getMsg());}
}

        事件处理

/*** 事件处理类**/
public class EventManager {public enum EventType{MQ,Message}//监听器集合Map<Enum<EventType>, List<EventListener>> listeners = new HashMap<>();public EventManager(Enum<EventType>... operations) {for (Enum<EventType> operation : operations) {this.listeners.put(operation,new ArrayList<>());}}/*** 订阅*/public void subscribe(Enum<EventType> eventType, EventListener listener){List<EventListener> users = listeners.get(eventType);users.add(listener);}/*** 取消订阅*/public void unsubscribe(Enum<EventType> eventType,EventListener listener){List<EventListener> users = listeners.get(eventType);users.remove(listener);}/*** 通知*/public void notify(Enum<EventType> eventType, LotteryResult result){List<EventListener> users = listeners.get(eventType);for (EventListener listener : users) {listener.doEvent(result);}}
}

        摇号业务处理

/*** 开奖服务接口**/
public abstract class LotteryService{private EventManager eventManager;public LotteryService(){//设置事件类型eventManager = new EventManager(EventManager.EventType.MQ, EventManager.EventType.Message);//订阅eventManager.subscribe(EventManager.EventType.Message,new MessageEventListener());eventManager.subscribe(EventManager.EventType.MQ,new MQEventListener());}public LotteryResult lotteryAndMsg(String uId){LotteryResult result = lottery(uId);//发送通知eventManager.notify(EventManager.EventType.Message,result);eventManager.notify(EventManager.EventType.MQ,result);return result;}public abstract LotteryResult lottery(String uId);
}
/*** 开奖服务**/
public class LotteryServiceImpl extends LotteryService {//注入摇号服务private DrawHouseService houseService = new DrawHouseService();@Overridepublic LotteryResult lottery(String uId) {//摇号String result = houseService.lots(uId);return new LotteryResult(uId,result,new Date());}
}

        测试

@Test
public void test2(){LotteryService ls = new LotteryServiceImpl();LotteryResult result  = ls.lotteryAndMsg("1234567887654333");System.out.println(result);
}

4.JDK 中对观察者模式的支持

JDK中提供了Observable类以及Observer接口,它们构成了JDK对观察者模式的支持;

  • java.util.Observer 接口: 该接口中声明了一个方法,它充当抽象观察者,其中声明了一个update方法.

    void update(Observable o, Object arg);
  • java.util.Observable 类: 充当观察目标类(被观察类) , 在该类中定义了一个Vector集合来存储观察者对象.下面是它最重要的 3 个方法。

    • void addObserver(Observer o) 方法:用于将新的观察者对象添加到集合中。

    • void notifyObservers(Object arg) 方法:调用集合中的所有观察者对象的 update方法,通知它们数据发生改变。通常越晚加入集合的观察者越先得到通知。

    • void setChange() 方法:用来设置一个 boolean 类型的内部标志,注明目标对象发生了变化。当它为true时,notifyObservers() 才会通知观察者。

用户可以直接使用Observer接口和Observable类作为观察者模式的抽象层,再自定义具体观察者类和具体观察目标类,使用JDK中提供的这两个类可以更加方便的实现观察者模式.

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • MediaStream 的媒体流对象 (stream) 和流媒体轨道 (track) 详解
  • mysql多线程优化并行复制
  • Leetcode3259. 超级饮料的最大强化能量
  • 2024-pip install torch为CPU版本,GPU没有被使用的解决方法(windows和linux均适用)
  • uniapp动态页面API
  • 【生日视频制作】白色卡车行万里路车身改字1版AE模板修改文字软件生成器教程特效素材【AE模板】
  • 2.1概率统计的世界
  • SQL索引详解
  • 【百日算法计划】:每日一题,见证成长(010)
  • Linux:如何使用 Crontab
  • 标准库标头 <filesystem> (C++17)学习
  • 23种设计模式之责任链模式
  • Ubuntu基本命令的熟悉和使用
  • MongoDB创建用户教程
  • OpenCV结构分析与形状描述符(8)点集凸包计算函数convexHull()的使用
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • CSS 三角实现
  • egg(89)--egg之redis的发布和订阅
  • es6--symbol
  • JavaScript函数式编程(一)
  • k8s 面向应用开发者的基础命令
  • linux安装openssl、swoole等扩展的具体步骤
  • ng6--错误信息小结(持续更新)
  • php ci框架整合银盛支付
  • 对超线程几个不同角度的解释
  • 高度不固定时垂直居中
  • 聊聊redis的数据结构的应用
  • 思否第一天
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • 支付宝花15年解决的这个问题,顶得上做出十个支付宝 ...
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ###C语言程序设计-----C语言学习(6)#
  • #includecmath
  • #我与Java虚拟机的故事#连载18:JAVA成长之路
  • (20)docke容器
  • (js)循环条件满足时终止循环
  • (翻译)terry crowley: 写给程序员
  • (分布式缓存)Redis哨兵
  • (附源码)小程序 交通违法举报系统 毕业设计 242045
  • (七)理解angular中的module和injector,即依赖注入
  • (一)appium-desktop定位元素原理
  • ***利用Ms05002溢出找“肉鸡
  • . Flume面试题
  • .NET 4.0中的泛型协变和反变
  • .NET Core WebAPI中封装Swagger配置
  • .net core 客户端缓存、服务器端响应缓存、服务器内存缓存
  • .NET Core 通过 Ef Core 操作 Mysql
  • .NET/C# 使用反射调用含 ref 或 out 参数的方法
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .vue文件怎么使用_vue调试工具vue-devtools的安装
  • /etc/fstab和/etc/mtab的区别
  • []使用 Tortoise SVN 创建 Externals 外部引用目录
  • [1159]adb判断手机屏幕状态并点亮屏幕
  • [14]内置对象
  • [3D基础]理解计算机3D图形学中的坐标系变换