行为模式——观察者模式
一、定义
观察者模式是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。
二、问题
以订阅公众号为例,如果有人对某件产品感兴趣,那么就会订阅此公众号,它发布了新的产品都会通过公众号提醒订阅人;如果对此产品不感兴趣,那么就无需订阅,公众号也不会随时给你发送消息。
三、解决方案
要将自身的状态改变通知给其他对象称为发布者 (publisher)。
所有希望关注发布者状态变化的其他对象称为订阅者 (subscribers)。
观察者模式建议为发布者类添加订阅机制, 让每个对象都能订阅或取消订阅发布者事件流。 包括
1) 一个用于存储订阅者对象引用的列表成员变量
2) 几个用于添加或删除该列表中订阅者的公有方法
实际应用中可能会有十几个不同的订阅者类跟踪着同一个发布者类的事件, 我们不希望发布者与所有这些类相耦合的。 此外如果他人会使用发布者类, 那么你甚至可能会对其中的一些类一无所知。
因此, 所有订阅者都必须实现同样的接口, 发布者仅通过该接口与订阅者交互。 接口中必须声明通知方法及其参数, 这样发布者在发出通知时还能传递一些上下文数据。
四、代码实现
1、发布者 (Publisher) 会向其他对象发送值得关注的事件。 事件会在发布者自身状态改变或执行特定行为后发生。 发布者中包含一个允许新订阅者加入和当前订阅者离开列表的订阅构架。
package com.atmae.observe;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: Mae
* @Date: 2022/4/23
* @Time: 18:43
* @Description:
*/
public class OfficialAccounts {
private List<UserObserver> observerList=new ArrayList<>();
public void subscribe(UserObserver observer) {
this.observerList.add(observer);
}
public void unSubscribe(UserObserver observer) {
this.observerList.remove(observer);
}
/**
* 通知观察者/订阅者
*/
public void notifySubscribes() {
System.out.println("我要更改产品了啊");
for (UserObserver observer : observerList) {
observer.update();
}
}
}
2、订阅者 (Subscriber) 接口声明了通知接口。 在绝大多数情况下, 该接口仅包含一个 update更新方法。 该方法可以拥有多个参数, 使发布者能在更新时传递事件的详细信息。
package com.atmae.observe;
/**
* @Author: Mae
* @Date: 2022/4/23
* @Time: 18:59
* @Description: 抽象观察者
*/
public interface UserObserver {
void update();
}
3、
具体订阅者 (Concrete Subscribers) 可以执行一些操作来回应发布者的通知。 所有具体订阅者类都实现了同样的接口, 因此发布者不需要与具体类相耦合。
package com.atmae.observe;
/**
* @Author: Mae
* @Date: 2022/4/23
* @Time: 19:01
* @Description:
*/
public class ConcreteUserObserver1 implements UserObserver{
@Override
public void update() {
System.out.println("订阅者1收到了信息啦");
}
}
package com.atmae.observe;
/**
* @Author: Mae
* @Date: 2022/4/23
* @Time: 19:02
* @Description:
*/
public class ConcreteUserObserver2 implements UserObserver{
@Override
public void update() {
System.out.println("订阅者2收到信息啦");
}
}
4、客户端 (Client) 会分别创建发布者和订阅者对象, 然后为订阅者注册发布者更新。
package com.atmae.observe;
/**
* @Author: Mae
* @Date: 2022/4/23
* @Time: 19:08
* @Description:
*/
public class Client {
public static void main(String[] args) {
OfficialAccounts officialAccounts = new OfficialAccounts();
UserObserver observer1 = new ConcreteUserObserver1();
UserObserver observer2 = new ConcreteUserObserver2();
officialAccounts.subscribe(observer1);
officialAccounts.subscribe(observer2);
officialAccounts.notifySubscribes();
System.out.println("------------------------");
officialAccounts.unSubscribe(observer2);
officialAccounts.notifySubscribes();
}
}
五、UML图
六、观察者模式适用场景
-
当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。
-
当应用中的一些对象必须观察其他对象时, 可使用该模式。 但仅能在有限时间内或特定情况下使用。
七、总结
优点
- 开闭原则。 无需修改发布者代码就能引入新的订阅者类 (如果是发布者接口则可轻松引入发布者类)。
- 可以在运行时建立对象之间的联系。
缺点
- 订阅者的通知顺序是随机的