文章目录

  • 一、观察者模式简介
  • 二、观察者模式适用场景
  • 三、观察者模式优缺点
  • 四、观察者模式代码示例
    • 1、被观察者
    • 2、观察者
    • 3、通知类
    • 4、测试类
  • 五、JDK 中的观察者模式支持类
    • 1、Observable
    • 2、Observer

一、观察者模式简介


观察者模式 : 定义了 对象之间 一对多 的 依赖 , 令 多个 观察者 对象 同时 监听 某一个 主题对象 , 当 主题对象 发生改变时 , 所有的 观察者 都会 收到通知 并更新 ;

观察者 有多个 , 被观察的 主题对象 只有一个 ;

如 : 在购物网站 , 多个用户关注某商品后 , 当商品降价时 , 就会自动通知关注该商品的用户 ;

  • 主题对象 : 商品是主题对象 ;
  • 观察者 : 用户是观察者 ;
  • 观察者注册 : 用户关注 , 相当于注册观察者 ;
  • 通知触发条件 : 商品降价 ;

观察者模式 类型 : 行为型 ;

二、观察者模式适用场景


观察者模式适用场景 : 关联行为 场景 , 建立一套 触发机制 ;

如 : 用户关注某个商品的价格 , 降价时进行通知 , 这样 用户 和 商品 产生了关联 , 触发机制就是 商品降价 ,

三、观察者模式优缺点


观察者模式 优点 :

  • 抽象耦合 : 在 观察者 和 被观察者 之间 , 建立了一个 抽象的 耦合 ; 由于 耦合 是抽象的 , 可以很容易 扩展 观察者 和 被观察者 ;
  • 广播通信 : 观察者模式 支持 广播通信 , 类似于消息广播 , 如果需要接收消息 , 只需要注册一下即可 ;

观察者模式 缺点 :

  • 依赖过多 : 观察者 之间 细节依赖 过多 , 会增加 时间消耗 和 程序的复杂程度 ;
    这里的 细节依赖 指的是 触发机制 , 触发链条 ; 如果 观察者设置过多 , 每次触发都要花很长时间去处理通知 ;
  • 循环调用 : 避免 循环调用 , 观察者 与 被观察者 之间 绝对不允许循环依赖 , 否则会触发 二者 之间的循环调用 , 导致系统崩溃 ;

四、观察者模式代码示例


JDK 中提供了观察者模式的支持 ;

  • 被观察者 : 被观察者 继承 Observable 类 ;
  • 观察者 : 观察者 实现 Observer 接口 ;
  • 关联 观察者 与 被观察者 : 调用 被观察者 的 addObserver 方法 , 关联二者 ;
  • 触发通知 : 被观察者 数据改变时 , 调用 setChanged 和 notifyObservers 方法 , 会自动回调 观察者的 update 方法 ;

用户在游戏中提出问题 , 管理员负责监听并处理问题 ;

1、被观察者

package observer;import java.util.Observable;/*** 被观察的主题对象*      JDK 提供了对观察者模式的支持 , 被观察者可以继承 Observable 类** 被观察对象 继承 Observable 类*/
public class Game extends Observable {private String name;public Game(String name) {this.name = name;}public String getName() {return name;}/*** 用户提交问题* @param game* @param question*/public void produceQuestion(Game game, Question question) {System.out.println(question.getUserName() +" 在 " + game.name + " 游戏中提交问题 : " + question.getContent());// 该方法是 Observable 提供的方法// 将 private boolean changed = false 成员变量设置为 true// 代表 被观察者 的状态发生了改变setChanged();// 通知 观察者notifyObservers(question);}
}

2、观察者

package observer;import java.util.Observable;
import java.util.Observer;/*** 管理员类*      管理员类观察的是游戏*      用户反馈的问题 属于 游戏 , 管理员关注的是游戏*      无法关注 问题** 如 : 在电商平台 , 关注的是某个商品 , 在降价时发送通知*      商品是存在的 , 降价消息 在关注的时候还没有被创建 , 是无法获取依赖的*/
public class Manager implements Observer {/*** 管理员名称*/private String name;public Manager(String name) {this.name = name;}@Overridepublic void update(Observable o, Object arg) {// 获取 被观察者 对象Game game = (Game) o;// 获取 被观察者 对象 调用 notifyObservers 方法的参数Question question = (Question) arg;System.out.println(name + " 观察者 接收到 被观察者 " + game.getName() +" 的通知 , 用户 " + question.getUserName() +" 提出问题 " + question.getContent());}
}

3、通知类

package observer;public class Question {/*** 用户名*/private String userName;/*** 问题内容*/private String content;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}
}

4、测试类

package observer;public class Main {public static void main(String[] args) {// 创建被观察者Game game = new Game("Cat And Mouse");// 创建观察者Manager manager = new Manager("Tom");// 关联 观察者 与 被观察者game.addObserver(manager);// 业务逻辑 : 用户提出问题到游戏中 , 管理员接收到通知消息Question question = new Question();question.setUserName("Jerry");question.setContent("游戏崩溃");// 在游戏中提交问题game.produceQuestion(game, question);}
}

执行结果 :

Jerry 在 Cat And Mouse 游戏中提交问题 : 游戏崩溃
Tom 观察者 接收到 被观察者 Cat And Mouse 的通知 , 用户 Jerry 提出问题 游戏崩溃

五、JDK 中的观察者模式支持类


1、Observable

被观察者需要继承该类 ;

public class Observable {private boolean changed = false;/** 使用 Vector 是线程安全的集合 , 存放观察者对象 , 在构造器中初始化该类 */private Vector<Observer> obs;/** Construct an Observable with zero Observers. */public Observable() {obs = new Vector<>();}/*** 添加观察者对象 , 采用了 synchronized 修饰 , 是同步方法 , 保证了线程安全 ** @param   o   an observer to be added.* @throws NullPointerException   if the parameter o is null.*/public synchronized void addObserver(Observer o) {if (o == null)throw new NullPointerException();if (!obs.contains(o)) {obs.addElement(o);}}/*** 删除观察者 */public synchronized void deleteObserver(Observer o) {obs.removeElement(o);}/*** 通知观察者 , 无参** @see     java.util.Observable#clearChanged()* @see     java.util.Observable#hasChanged()* @see     java.util.Observer#update(java.util.Observable, java.lang.Object)*/public void notifyObservers() {notifyObservers(null);}/*** 通知观察者 , 有参** @param   arg   any object.* @see     java.util.Observable#clearChanged()* @see     java.util.Observable#hasChanged()* @see     java.util.Observer#update(java.util.Observable, java.lang.Object)*/public void notifyObservers(Object arg) {Object[] arrLocal;synchronized (this) {if (!changed)return;arrLocal = obs.toArray();clearChanged();}for (int i = arrLocal.length-1; i>=0; i--)((Observer)arrLocal[i]).update(this, arg);}public synchronized void deleteObservers() {obs.removeAllElements();}protected synchronized void setChanged() {changed = true;}protected synchronized void clearChanged() {changed = false;}public synchronized boolean hasChanged() {return changed;}/*** 查看观察者数量 ** @return  the number of observers of this object.*/public synchronized int countObservers() {return obs.size();}
}

2、Observer

观察者需要实现该接口 ;

package java.util;/*** A class can implement the <code>Observer</code> interface when it* wants to be informed of changes in observable objects.** @author  Chris Warth* @see     java.util.Observable* @since   JDK1.0*/
public interface Observer {/*** 当 被观察者 对象发生改变时 , 即被观察者对象调用 notifyObservers 方法时 , 自动调用该方法** @param   o     被观察的对象.* @param   arg   被观察对象调用 notifyObservers 方法时传入的参数 */void update(Observable o, Object arg);
}

【设计模式】观察者模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )相关推荐

  1. 【设计模式】工厂方法模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

    文章目录 一.工厂方法模式简介 二.工厂方法模式适用场景 三.工厂方法模式优缺点 四.工厂方法模式代码示例 1.产品抽象类 2.产品实现类 1 3.产品实现类 2 4.抽象工厂类 5.实现工厂类 1 ...

  2. 【设计模式】责任链模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

    文章目录 一.责任链模式简介 二.责任链模式相关设计模式 三.责任链模式 代码示例 1.用户账户类 2.校验器父类 3.用户名校验器 4.密码校验器 5.电话号码校验器 6.运行测试 一.责任链模式简 ...

  3. 【设计模式】中介者模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

    文章目录 一.中介者模式简介 二.中介者模式适用场景 三.中介者模式优缺点 四.中介者模式 与 观察者模式 五.中介者模式 代码示例 1.聊天室 2.用户 3.运行实例 一.中介者模式简介 中介者模式 ...

  4. 【设计模式】模板方法模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

    文章目录 一.模板方法模式简介 二.模板方法模式适用场景 三.模板方法模式优缺点 四.模板方法扩展 五.模板方法模式相关设计模式 六.模板方法模式代码示例 1.模板方法抽象类 2.模板方法实现类 1 ...

  5. 【设计模式】策略模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

    文章目录 一.策略模式简介 二.策略模式适用场景 三.策略模式优缺点 四.策略模式与其它设计模式 五.策略模式代码示例 1.促销策略接口 2.满减促销策略 3.返现促销策略 4.空促销策略 5.促销策 ...

  6. 【设计模式】状态模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

    文章目录 一.状态模式简介 二.状态模式适用场景 三.状态模式优缺点 四.状态模式相关设计模式 五.状态模式代码示例 1.状态类父类 2.播放状态类 3.暂停状态类 4.快进状态类 5.停止状态类 6 ...

  7. 【设计模式】访问者模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

    文章目录 一.访问者模式简介 二.访问者模式 适用场景 三.访问者模式 优缺点 四.访问者模式 与 迭代器模式 五.代码示例 1.Game 父类 ( 被访问者 ) 2.VipGame 收费游戏 ( 被 ...

  8. 【设计模式】桥接模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

    文章目录 一.桥接模式简介 二.桥接模式适用场景 三.桥接模式优缺点 四.桥接模式相关设计模式 五.桥接模式代码示例 1.视频格式抽象 2.FLV 视频格式实现 3.MP4 视频格式实现 4.系统平台 ...

  9. 【设计模式】解释器模式 ( 简介 | 适用场景 | 优缺点 | 代码示例 )

    文章目录 一.解释器模式简介 二.解释器模式适用场景 三.解释器模式优缺点 四.解释器模式与适配器模式 五.解释器模式代码示例 1.解释器接口 2.加法解释器 3.乘法解释器 4.整型解释器 5.语法 ...

最新文章

  1. 浩方平台CS流量评估
  2. 分布式为什么一定要有高可用的分布式锁?一线大厂必看!
  3. 如何使用ASINetWorkQueue下载实现
  4. 数据采集之解析Mysql的binlog日志发送至Kafka实时消费(转:https://blog.csdn.net/liguohuabigdata/article/details/79472777)
  5. CSS一个冒号是伪类:用于监控动作、两个冒号是伪元素::用于定位元素
  6. 新浪微博:大规模离线视频处理系统的架构设计
  7. apache+tomcat+jk配置负载均衡
  8. unity3d在菜单栏,一键设置Player setting及自动打包并设置apk的存储位置
  9. 虚幻引擎C++开发学习(三)
  10. autojs脚本代码大全(实战演练1)
  11. 数据库:PostgreSQL:客户端安装
  12. 泛微e9隐藏明细表_泛微Ecology权限整理大全,相当全要点
  13. linux 查看链接文件,Linux下的链接文件详解
  14. win11浏览器默认主页如何设置
  15. iOS 9 spotlight搜索 3DTouch
  16. 记一次在vue项目上使用七牛文件上传的坑
  17. 我的分形屏保 国王风暴《KingBlizzard》
  18. Python之斐波那契
  19. shellcode免杀框架内附SysWhispers2_x86直接系统调用
  20. 常用小波基函数以及多尺度多分辨率的理解1

热门文章

  1. 那些年借“云”出海的日子
  2. 站长图卦:每天坚持搬砖 定有美好明天
  3. 全球IPv6网络6月6日正式启动
  4. easyUI menu动态添加
  5. Zepto.js简介
  6. linq to sql实战
  7. 用一个栈实现另一个栈的排序
  8. netsh winsock reset
  9. note-删除Visual Studio recent Projects list
  10. 第二节 RabbitMQ配置