初识设计模式 - 观察者模式
2023-02-19 12:17:23 时间
简介
观察者设计模式(Observer Design Pattern)的别名有很多,如发布 - 订阅(Publish/Subscribe)模式、模型 - 视图(Model/View)模式、源 - 监听(Source/Listener)模式或从属者(Dependents)模式。
无论是何种名称,其意图都是在对象之间定义一个一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。
其主要解决了一个对象状态改变之后给其他对象通知的问题,而且考虑到易用性和低耦合,保证高度的协作性。
典型实现
在发布 - 订阅模式当中,观察者就是订阅者,一般是需要定义一个抽象的观察者接口,其代码示例如下:
public interface Observer {
void update();
}
具体的观察者类也很简单,只需要简单实现接口即可,其代码示例如下:
public class ConcreteObserver implements Observer {
// 实现响应方法
public void update() {
// 具体响应代码
}
}
定义完订阅者,其次就是发布者,通常是将之定义为一个抽象的目标类,其代码示例如下:
public abstract class Subject {
// 定义一个观察者集合存储所有观察者对象
protected List<Observer> observers = new ArrayList<>();
// 注册方法,用于向观察者集合增加一个观察者
public void attach(Observer observer) {
observers.add(observer);
}
// 注销方法,用于向观察者集合删除一个观察者
public void detach(Observer observer) {
observers.remove(observer);
}
// 声明抽象的通知方法,需要由子类具体实现
abstract void notifyObservers();
}
根据不同的场景定义不一样的具体目标类,如下是一种代码示例:
public class ConcreteSubject extends Subject {
// 实现具体的通知方法
@Override
public void notifyObservers() {
// 遍历观察者集合,调用每一个观察者的响应方法
for (Observer ob : observers) {
ob.update();
}
}
}
总结
优点
观察者模式的主要优点如下:
- 观察者模式可以实现表示层和数据逻辑层的分离
- 观察者模式在观察目标和观察者之间建立了一个抽象的耦合
- 观察者模式支持广播通信,简化了一对多系统设计的难度
- 增加新的具体观察者无需修改原有代码,符合开闭原则
缺点
观察者模式的主要缺点如下:
- 如果目标对象的观察者有很多,将所有的观察者都通知到会非常耗时
- 如果目标对象和观察者存在循环依赖,观察目标会触发它们之间进行循环调用,最终导致系统崩溃
适用场景
观察者模式的适用场景如下:
- 将具有依赖关系的两种抽象模型独立出来,使它们可以独立地改变和复用
- 一个对象的改变将导致一个或多个其他对象也发生改变,但并不知道具体有多少对象将发生改变,也不知道这些对象是谁
- 可以使用观察者模式创建一种链式触发机制
源码
在 JDK 的 java.util
包中,提供了 Observer
接口和 Observable
类,它们构成了 JDK 对观察者模式的支持。
如下是 Observer
接口的源码:
@Deprecated(since = "9")
public interface Observer {
void update(Observable o, Object arg);
}
如下是 Observable
类的部分源码:
@Deprecated(since = "9")
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);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
需要注意的是,在 JDK 9 之后已经不推荐使用 Observer
接口和 Observable
类。
相关文章
- Jgit的使用笔记
- 利用Github Action实现Tornadofx/JavaFx打包
- 叹息!GitHub Trending 即将成为历史!
- 微软软了?开源社区讨论炸锅,GitHub CEO 亲自来答
- GitHub Trending 列表频现重复项,前后端都没去重?
- Photoshop Elements 2021版本软件安装教程(mac+windows全版本都有)
- (ps全版本)Photoshop 2020的安装与破解教程(mac+windows全版本都有)
- (ps全版本)Photoshop cc2018的安装与破解教程(mac+windows全版本,包括2023
- 环境搭建:Oracle GoldenGate 大数据迁移到 Redshift/Flat file/Flume/Kafka测试流程
- 每个开发人员都要掌握的:最小 Linux 基础课
- 来撸羊毛了!Windows 环境下 Hexo 博客搭建,并部署到 GitHub Pages
- 超实用!手把手入门 MongoDB:这些坑点请一定远离
- 【GitHub日报】22-10-09 zustand、neovim、webtorrent、express 等4款App今日上新
- 【GitHub日报】22-10-10 brew、minio、vite、seaweedfs、dbeaver 等8款App今日上新
- 【GitHub日报】22-10-11 cobra、grafana、vue、ToolJet、redwood 等13款App今日上新
- Photoshop 2018 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2017 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2020 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2023 资源免费下载(mac+windows全版本都有,包括最新的2023)
- 最新版本Photoshop CC2018软件安装教程(mac+windows全版本都有,包括2023