观察者模式(OBSERVER),又称发布-订阅(Publish-Subscribe),依赖(Dependents),通过定义对象间的一对多的依赖关系,达到当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新,属于对象行为型模式。观察者模式在软件设计中很常用,比如经典的MVC模式,Model为目标类,View为观察者,Controller为更新管理器。首先更新管理器即控制器先将视图和模型建立关联关系,然后当模型数据改变时,这些改变会自动反映在视图上,从而达到了业务和显示分离的效果。Java默认支持观察者模式,AWT1.1之后版本,Servlet,SAX2的事件处理模型均为基于观察者模式的委托事件模型(Delegation Event Model或DEM)。在DEM模型里面,主题(Subject)角色负责发布(publish)事件,而观察者角色向特定的主题订阅(subscribe)它所感兴趣的事件。当一个具体主题产生一个事件时,它就会通知所有感兴趣的订阅者。观察者模式提供了一种将发布者与订阅者松散地耦合在一起的联系形式,以及一种能够动态地登记、取消向一个发布者的订阅请求的办法。

一、使用场景

1、当一个抽象模型有两个方面,其中一个方面依赖于另一方面,将这两者封装在独立的对象中以使它们能够独立地改变和复用。

2、当对一个对象的改变需要同时改变其他对象,而又不知道具体有多少对象及这些对象是谁。

3、建立链式触发机制,A影响B,B影响C,C影响D等等。

二、UML图

三、Java实现

[java]  view plain copy
  1. package study.patterns.observer;
  2. import java.text.SimpleDateFormat;
  3. import java.util.ArrayList;
  4. import java.util.Date;
  5. import java.util.List;
  6. /**
  7. * 观察者模式
  8. * @author qbg
  9. */
  10. public class ObserverPattern {
  11. public static void main(String[] args) {
  12. ClockTimerSubject timer = new ClockTimerSubject();//目标
  13. DigitalClock digital = new DigitalClock(timer);//观察者
  14. BigBenClock bigben = new BigBenClock(timer);//观察者
  15. TimerTask task = new TimerTask(timer);//定时任务
  16. task.start();//启动定时任务
  17. }
  18. }
  19. /**
  20. * 抽象目标类
  21. */
  22. abstract class Subject{
  23. protected List<Observer> observers = new ArrayList<Observer>();
  24. /**
  25. *  注册观察者
  26. */
  27. public void attach(Observer obs){
  28. observers.add(obs);
  29. }
  30. /**
  31. * 删除观察者
  32. */
  33. public void detach(Observer obs){
  34. observers.remove(obs);
  35. }
  36. /**
  37. * 通知观察者的抽象方法
  38. */
  39. public abstract void notifyObs();
  40. }
  41. /**
  42. * 具体目标类,每秒更新下自己的内部时间状态
  43. */
  44. class ClockTimerSubject extends Subject{
  45. private String time;
  46. /**
  47. * 具体通知方式,通知所有观察者
  48. */
  49. @Override
  50. public void notifyObs() {
  51. for(Observer obs : this.observers){
  52. obs.update(this);
  53. }
  54. }
  55. /**
  56. * 更新time,并将改变通知给观察者
  57. */
  58. public void tick(){
  59. SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  60. time = sdf.format(new Date());
  61. notifyObs();
  62. }
  63. public String getTime() {
  64. return time;
  65. }
  66. public void setTime(String time) {
  67. this.time = time;
  68. }
  69. }
  70. /**
  71. * 观察者抽象接口,只有一个update方法
  72. */
  73. interface Observer{
  74. public void update(ClockTimerSubject subject);
  75. }
  76. /**
  77. * 钟表绘制接口
  78. */
  79. interface Widget{
  80. public void draw();
  81. }
  82. /**
  83. * 数字钟表,具体观察者
  84. */
  85. class DigitalClock implements Widget,Observer{
  86. private ClockTimerSubject subject;
  87. /**
  88. * 初始化目标,并将自己注册到该目标的观察者列表中
  89. */
  90. public DigitalClock(ClockTimerSubject subject){
  91. this.subject = subject;
  92. this.subject.attach(this);
  93. }
  94. /**
  95. * 先检查发出通知的目标是否为自己注册过的,是则响应
  96. */
  97. @Override
  98. public void update(ClockTimerSubject subject) {
  99. if(this.subject == subject){
  100. draw();
  101. }
  102. }
  103. @Override
  104. public void draw() {
  105. System.out.println("电子闹钟为您报时:"+subject.getTime());
  106. }
  107. }
  108. /**
  109. * 大笨钟,具体观察者
  110. */
  111. class BigBenClock implements Widget,Observer{
  112. private ClockTimerSubject subject;
  113. /**
  114. * 初始化目标,并将自己注册到该目标的观察者列表中
  115. */
  116. public BigBenClock(ClockTimerSubject subject){
  117. this.subject = subject;
  118. this.subject.attach(this);
  119. }
  120. /**
  121. * 先检查发出通知的目标是否为自己注册过的,是则响应
  122. */
  123. @Override
  124. public void update(ClockTimerSubject subject) {
  125. if(this.subject == subject){
  126. draw();
  127. }
  128. }
  129. @Override
  130. public void draw() {
  131. System.out.println("伦敦大笨钟为您报时:"+subject.getTime());
  132. }
  133. }
  134. /**
  135. * 定时任务,每秒更新一次ClockTimerSubject的状态
  136. */
  137. class TimerTask extends Thread{
  138. private ClockTimerSubject timer;
  139. public TimerTask(ClockTimerSubject timer){
  140. this.timer = timer;
  141. }
  142. @Override
  143. public void run() {
  144. while(true){
  145. try {
  146. timer.tick();
  147. Thread.sleep(1000);
  148. } catch (InterruptedException e) {
  149. e.printStackTrace();
  150. }
  151. }
  152. }
  153. }

运行结果:

[plain]  view plain copy
  1. 电子闹钟为您报时:2014-02-12 21:44:48
  2. 伦敦大笨钟为您报时:2014-02-12 21:44:48
  3. 电子闹钟为您报时:2014-02-12 21:44:49
  4. 伦敦大笨钟为您报时:2014-02-12 21:44:49
  5. 电子闹钟为您报时:2014-02-12 21:44:50
  6. 伦敦大笨钟为您报时:2014-02-12 21:44:50
  7. 电子闹钟为您报时:2014-02-12 21:44:51
  8. 伦敦大笨钟为您报时:2014-02-12 21:44:51

四、模式优缺点

优点:

1、目标和观察者间的抽象耦合。目标仅知道它有一系列符合抽象接口Observer的观察者,而不知道这些观察者属于哪个具体的类,这样目标和观察者之间的耦合就是抽象的和最小的。

2、支持广播通信。观察目标会向所有已注册的观察者对象发送通知,具体如何处理通知由观察者决定,简化了一对多系统的设计难度。

缺点:

1、意外的更新。由于观察者仅仅知道目标改变了,而不晓得具体什么被改变了,目标上的一个看似无害的操作可能会引起一系列对观察者及依赖于这些观察者的对象的更新,导致错误的产生。

设计模式初探-观察者模式相关推荐

  1. 设计模式初探-观察者模式(OBSERVER)又称发布-订阅(Publish-Subscribe)依赖(Dependents)

    观察者模式(OBSERVER),又称发布-订阅(Publish-Subscribe),依赖(Dependents),通过定义对象间的一对多的依赖关系,达到当一个对象的状态发生改变时,所有依赖于它的对象 ...

  2. 设计模式:观察者模式--Observer

    一.什么是观察者模式 1.生活中的观察者模式 1.警察抓小偷 在现实生活中,警察抓小偷是一个典型的观察者模式「这以一个惯犯在街道逛街然后被抓为例子」,这里小偷就是被观察者,各个干警就是观察者,干警时时 ...

  3. java 观察者模式_图解Java设计模式之观察者模式

    图解Java设计模式之观察者模式 天气预报项目需求 天气预报设计方案 1 - 普通方案 观察者模式(Observer)原理 观察者模式解决天气预报需求 观察者模式在JDK应用的源码分析 天气预报项目需 ...

  4. 游戏服务器架构-设计模式之观察者模式和发布订阅模式真的一样吗?

    前面我给大家分享了观察者模式和发布订阅模式,有人私信给我说这俩不是一样嘛,大体没什么区别,我猜测大多数认为这两者是一样的可以继续阅读这两篇文章,如果还不能解答你的问题,我相信这篇文章对比两者的关系会让 ...

  5. java设计模式观察者模式吗_Java设计模式之观察者模式原理与用法详解

    Java设计模式之观察者模式原理与用法详解 本文实例讲述了Java设计模式之观察者模式原理与用法.分享给大家供大家参考,具体如下: 什么是观察者模式 可以这么理解: 观察者模式定义了一种一对多的依赖关 ...

  6. 设计模式 C++观察者模式

    无论是在现实世界中还是在软件系统中,人们常常会遇到这样一类问题,一个对象的状态改变会引发其他对象的状态改变,如十字路口的交通信号灯,红灯亮则汽车停,绿灯亮则汽车行,再如点击软件中一个按钮,则会弹出一个 ...

  7. 学习《图说设计模式》观察者模式

    图说设计模式之观察者模式 1. 模式动机 建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应做出反应.在此,发生改变的对象称为观察目标,而被通知的对象称为观察者,一 ...

  8. 设计模式之观察者模式——猫抓老鼠2

    设计模式之观察者模式--猫抓老鼠2: 对猫抓老鼠1再次进行优化,降低代码复杂性,以及使用事件来对方法进行保护 代码优化: 将老鼠代码进行优化,将自己的方法在构造时便注册到猫里面: using Syst ...

  9. 设计模式之观察者模式——猫抓老鼠1

    设计模式之观察者模式--猫抓老鼠: 问题描述: 通过猫抓老鼠的例子进行了解观察者模式,首先的初始代码为(有三个类): using System;/// <summary> /// 观察者设 ...

最新文章

  1. 使用雪花id或uuid作为Mysql主键,被老板怼了一顿!
  2. BZOJ 1192 鬼谷子的钱袋 数论
  3. linux6.6系统安装,CentOS6.6系统怎么安装
  4. PHP完整的一次请求过程:请求 dns nginx监听 转发给php-fpm worker处理 返给nginx
  5. 百度编辑器ueditor 字符限制
  6. 如何解决“已有打开的与此命令相关联的 DataReader,必须首先将它关闭。”
  7. 什么叫侧面指纹识别_屏幕指纹技术最强的3款全面屏手机,指纹识别技术手机你喜欢吗?...
  8. Install load test reports
  9. python对文本的处理_Python 基础 - 对文本的处理
  10. 2017ps计算机考证
  11. 【python量化】统计套利之配对交易策略实现(基于python)
  12. mybatis根据日期范围查询,多参数查询
  13. 服务器硬盘和普通硬盘驱动安装,固态硬盘与硬盘驱动器的区别及怎样选择
  14. pwnable-passcode
  15. 【excel】开启了循环引用怎么关闭
  16. 服务过美国总统竞选的非传统投票UI【demo已放出】
  17. MIT 6.824学习-GFS
  18. 2022企业级BI平台白皮书(附下载)
  19. Java的图标及由来(9.25)
  20. 常见的电脑屏幕分辨率统计

热门文章

  1. 华为电脑浏览器主页被劫持
  2. 小麦苗的微信公众号开通啦,欢迎大家扫码关注
  3. python websocket实时消息推送
  4. 窗口看门狗和独立看门狗区别
  5. 一道简单的逻辑运算题
  6. c++ shared_ptr的reset(), get()
  7. android用shape画虚线,怎么也不显示
  8. 【Unity数据持久化】Ixmllserializable接口的使用
  9. 2020.04.16今日份学习小结
  10. 做好多项目管理的十个关键步骤(含工具)