1. 概念
观察者模式是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。
观察者模式的应用场景挺常见的,他还有另外一个名字,说出来你大概就懂了这个模式是在干什么的,叫做订阅——发布者模式,是不是突然就有想法了,我们下面先从具体使用场景来引入它。
假如你有两种类型的对象: 顾客和 商店 。 顾客对商店里的iPhone最新版非常感兴趣, 而该产品很快将会在商店里出售。顾客可以每天来商店看看产品是否到货。 但如果商品尚未到货时, 绝大多数来到商店的顾客都会空手而归。
另一方面, 每次新产品到货时, 商店可以向所有顾客发送邮件 (可能会被视为垃圾邮件)。 这样, 部分顾客就无需反复前往商店了, 但也可能会惹恼对新产品没有兴趣的其他顾客。
我们似乎遇到了一个矛盾: 要么让顾客浪费时间检查产品是否到货, 要么让商店浪费资源去通知没有需求的顾客。
那现在该怎么做才是比较好的解决方式呢?答案就是我们把对这个商品感兴趣的用户登记好,等商品来的时候商店去通知客户,然后客户再来买,这个逻辑其实在现实生活中也很常见。这样一来,既不会让用户白跑一趟,也不会惹恼对商品不感兴趣的客户。okk,这就是观察者模式,那具体实现我们看下面。
- 总结: 观察者模式用于解决订阅——发布的问题,解决方法是登记特定客户,对特定客户推送通知。
2. 特点
-
优点
- 开闭原则。 你无需修改发布者代码就能引入新的订阅者类 (如果是发布者接口则可轻松引入发布者类)。
- 你可以在运行时建立对象之间的联系。
-
缺点:订阅者的通知顺序是随机的。
-
使用场景
-
当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。
当你使用图形用户界面类时通常会遇到一个问题。 比如, 你创建了自定义按钮类并允许客户端在按钮中注入自定义代码, 这样当用户按下按钮时就会触发这些代码。
观察者模式允许任何实现了订阅者接口的对象订阅发布者对象的事件通知。 你可在按钮中添加订阅机制, 允许客户端通过自定义订阅类注入自定义代码。
-
当应用中的一些对象必须观察其他对象时, 可使用该模式。 但仅能在有限时间内或特定情况下使用。订阅列表是动态的, 因此订阅者可随时加入或离开该列表。
-
3. 实现
-
UML类图
-
Java代码
- 发布者
/** * @Author: chy * @Description: 发布者,商店 * @Date: Create in 11:49 2021/3/31 */ public class Shop { // 状态,1表示有货 private int state = 0; // 登记的客户名单 private List<Custom> customList = new ArrayList<>(); // 进货 public void stock(){ this.state = 1; } // 注册订阅者 public void register(Custom custom){ customList.add(custom); } // 通知订阅者 public void call(){ if (state == 1){ for (Custom custom : customList) { custom.buy(); } } } }
- 订阅者
/** * @Author: chy * @Description: 订阅者,顾客 * @Date: Create in 11:52 2021/3/31 */ public class Custom { // 顾客购买iphone public void buy(){ System.out.println("买东西了~~~~"); } }
- 客户端
/** * @Author: chy * @Description: 客户端 * @Date: Create in 11:49 2021/3/31 */ public class Client { public static void main(String[] args) { Shop shop = new Shop(); Custom custom1 = new Custom(); Custom custom2 = new Custom(); // 注册订阅者 shop.register(custom1); shop.register(custom2); // 商品到货 shop.stock(); // 通知客户 shop.call(); } }
- 结果
- 发布者