【设计模式】观察者模式 ( 简介
智能空调的自动模式设置和节能模式介绍 #生活技巧# #居家生活技巧# #电器维修技巧# #智能电器操作手册#
文章目录 一、观察者模式简介二、观察者模式适用场景三、观察者模式优缺点四、观察者模式代码示例1、被观察者2、观察者3、通知类4、测试类 五、JDK 中的观察者模式支持类1、Observable2、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); } }
1234567891011121314151617181920212223242526272829303132333435363738392、观察者
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; } @Override public 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()); } }
123456789101112131415161718192021222324252627282930313233343536373、通知类
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; } }
12345678910111213141516171819202122232425262728294、测试类
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); } }
123456789101112131415161718192021执行结果 :
Jerry 在 Cat And Mouse 游戏中提交问题 : 游戏崩溃 Tom 观察者 接收到 被观察者 Cat And Mouse 的通知 , 用户 Jerry 提出问题 游戏崩溃 12
五、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(); } }
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889902、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); }
1234567891011121314151617181920网址:【设计模式】观察者模式 ( 简介 https://www.yuejiaxmz.com/news/view/122844
相关内容
【设计模式】策略模式 ( 简介【设计模式】解释器模式 ( 简介
设计模式生活实例
如何从生活中领悟设计模式
23种设计模式总结及应用场景
设计模式
从生活中领悟设计模式
生活摄影模式的技巧介绍
楷模家居:不为设计的设计=*的设计
楷模家居:不为设计的设计=最好的设计