Fork me on GitHub

【趣味设计模式系列】之【观察者模式】

 


1. 简介

观察者模式(Observer Pattern),也叫做发布订阅模式(Publish-Subscribe),它定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

2. 图解

水果店进口水果销量良好,特别是进口蛇果,目前还没到货,有几个女孩小美、小静、小陶想预定进口蛇果,在到货之前就给水果老板说过,等到货后电话或者微信第一时间通知她们。

3. 案例实现

类图如下

  • 定义预定顾客为观察者接口Observer,当收到被观察者通知后,执行update()方法;
  • 定义水果店水果为被观察者抽象类FruitObservable,持有一个类型为Vector<Observer>的属性,存放观察者集合,同时定义三个方法addObserver()deleteObserver()notifyObservers(),分别为添加预定顾客,删除预定顾客,通知已预订顾客;
  • 定义FruitObservable抽象接口的实现类为进口蛇果ImportedRedDeliciousApple
  • 定义Observer接口的实现类为预定进口蛇果的客户类CustomerObserver

代码实现如下

package com.wzj.observer.example1; /** * @Author: wzj * @Date: 2019/10/3 14:53 * @Desc: 观察者接口类 */ public interface Observer { //收到通知后观察者更新 void update(); }
package com.wzj.observer.example1; import java.util.Vector; /** * @Author: wzj * @Date: 2019/10/3 14:50 * @Desc: 水果店被观察者类 */ public abstract class FruitObservable { //线程安全的容器类 protected Vector<Observer> obs = new Vector<>(); //添加预定顾客 public void addObserver(Observer o) { obs.addElement(o); } //删除固定顾客 public void deleteObserver(Observer o) { obs.removeElement(o); } //通知已预定顾客 public abstract void notifyObservers(); }
package com.wzj.observer.example1; /** * @Author: wzj * @Date: 2019/10/3 15:19 * @Desc: 进口蛇果类 */ public class ImportedRedDeliciousApple extends FruitObservable { @Override public void notifyObservers() { System.out.println("通知: 进口蛇果已到..."); for(Observer o : obs) { //通知每位预定顾客 o.update(); } } }
package com.wzj.observer.example1; /** * @Author: wzj * @Date: 2019/10/3 15:25 * @Desc: 预定进口蛇果的客户类 */ public class CustomerObserver implements Observer { //观察者姓名 private String name; public CustomerObserver(String name){ this.name = name; } @Override public void update() { System.out.println(name + "已收到通知, 将立马过来购买!"); } }

客户端测试类

package com.wzj.observer.example1; /** * @Author: wzj * @Date: 2019/10/3 15:38 * @Desc: */ public class Client { public static void main(String[] args) { //进口蛇果 ImportedRedDeliciousApple apple = new ImportedRedDeliciousApple(); //初始化预定客户类 CustomerObserver mei = new CustomerObserver("小美"); CustomerObserver jing = new CustomerObserver("小静"); CustomerObserver tao = new CustomerObserver("小陶"); //将小美、小静、小陶加入水果店的预定客户列表中 apple.addObserver(mei); apple.addObserver(jing); apple.addObserver(tao); //通知客户 apple.notifyObservers(); } }

执行结果如下

通知: 进口蛇果已到... 小美已收到通知, 将立马过来购买! 小静已收到通知, 将立马过来购买! 小陶已收到通知, 将立马过来购买!

3. JDK中自带实现与源码分析

类图如下

  • JDK自带接口Observer,当收到被观察者通知后,执行update()方法;
  • JDK自带接口Observableboolean类型的属性changed表示状态是否变化,持有一个类型为Vector<Observer>的属性obs
  • 定义Observable抽象接口的实现类为进口蛇果ImportedRedDeliciousApple
  • 定义Observer接口的实现类为预定进口蛇果的客户类CustomerObserver

代码实现如下

package com.wzj.observer.example2; import java.util.Observable; import java.util.Observer; /** * @Author: wzj * @Date: 2019/10/3 17:09 * @Desc: 预定客户类,继承观察者接口 */ public class CustomerObserver implements Observer { private String name; public CustomerObserver(String name){ this.name = name; } @Override public void update(Observable o, Object arg) { System.out.println(name + "已收到通知, 将立马过来购买!"); } }
package com.wzj.observer.example2; import java.util.Observable; import java.util.Observer; /** * @Author: wzj * @Date: 2019/10/3 17:02 * @Desc: 进口蛇果类,继承jdk的Observable接口 */ public class ImportedRedDeliciousApple extends Observable { public void peform() { System.out.println("通知: 进口蛇果已到..."); //设置状态改变 this.setChanged(); this.notifyObservers(); } }

客户端代码如下

package com.wzj.observer.example2; /** * @Author: wzj * @Date: 2019/10/3 15:38 * @Desc: 使用jdk自带的Observable类和Observer接口 */ public class Client { public static void main(String[] args) { //进口蛇果 ImportedRedDeliciousApple apple = new ImportedRedDeliciousApple(); //初始化预定客户类 CustomerObserver mei = new CustomerObserver("小美"); CustomerObserver jing = new CustomerObserver("小静"); CustomerObserver tao = new CustomerObserver("小陶"); //将小美、小静、小陶加入水果店的预定客户列表中 apple.addObserver(mei); apple.addObserver(jing); apple.addObserver(tao); //通知客户 apple.peform(); } }

执行结果

通知: 进口蛇果已到... 小陶已收到通知, 将立马过来购买! 小静已收到通知, 将立马过来购买! 小美已收到通知, 将立马过来购买!

源码分析

/** 被观察者 */ public class Observable { private boolean changed = false; private Vector<Observer> obs; /** 构造方法 */ public Observable() { obs = new Vector<>(); } /** 添加观察者,并加同步控制保证多线程安全 */ 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); } /** 通知观察者 */ public void notifyObservers() { //通知所有观察者 notifyObservers(null); } 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); } /** 状态改变 */ protected synchronized void setChanged() { changed = true; }

4. 观察者模式总结

优点

  • 观察者和被观察者之间是抽象耦合。
    不管是增加观察者还是被观察者都非常容易扩展,而且在Java中都已经实现的抽象层级的定义,所以尽量使用JDK自带的接口。

  • 与责任链结合使用
    在很多系统中,Observer模式往往和责任链共同负责对于事件的处理,其中的某一个observer负责是否将事件进一步传递。

缺点
观察者模式需要考虑一下开发效率和运行效率问题,一个被观察者,多个观察者,开发和调试就会比较复杂,而且在Java中消息的通知默认是顺序执行,一个观察者卡壳,会影响整体的执行效率。在这种情况下,一般考虑采用异步的方式。


__EOF__

本文作者小猪爸爸
本文链接https://www.cnblogs.com/father-of-little-pig/p/11629810.html
关于博主:不要为了技术而技术,总结分享技术,感恩点滴生活!
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   小猪爸爸  阅读(388)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示