JavaScript设计模式:观察者模式
模式概念
在软件系统中,某个对象的状态或行为的变化将导致其他对象的状态或行为也发生改变,从而产生联动。观察者模式是一种典型的行为设计模式,定义了对象之间的一对多依赖关系,使得一个对象的状态改变时,其所有依赖者都会得到通知并自动更新。
- 观察目标(Subject):发生改变的对象。
- 观察者(Observer):被通知的对象。
- 观察者模式是一种对象行为型模式,通常用于事件驱动的场景。
模式结构
观察者模式包含以下几个主要角色:
- Subject(目标):目标对象,它持有观察者的集合,并提供添加、删除观察者的方法。当目标对象状态改变时,它负责通知所有观察者。
- Observer(观察者):定义观察者接口,包含一个
update()
方法,观察者通过此方法作出响应。 - ConcreteObserver(具体观察者):观察者的具体实现类,实现了
update()
方法。 - ConcreteSubject(具体目标):目标的具体实现类,在其状态改变时通知观察者。
代码实现
以一个简单的例子来实现观察者模式:假设猫是老鼠和狗的观察目标,老鼠和狗是观察者,当猫叫时,老鼠会跑,狗会跟着叫。
// 观察目标类:猫
class Subject {
constructor() {
this.observers = []; // 观察者集合
}
// 添加观察者
add(observer) {
this.observers.push(observer);
}
// 移除观察者
delete(name) {
this.observers = this.observers.filter(e => e.name !== name);
}
// 通知所有观察者
notify() {
this.observers.forEach(item => {
item.update();
});
}
}
// 抽象观察者
class Observer {
constructor(name) {
this.name = name;
}
// 观察者更新逻辑
update() {
console.log(`观察者${this.name}做出响应`);
}
}
// 具体观察者:老鼠
class MouseObserver extends Observer {
constructor(name) {
super(name);
}
run() {
console.log(`${this.name}跑起来`);
}
update() {
console.log(`观察者${this.name}做出响应`);
this.run();
}
}
// 具体观察者:狗
class DogObserver extends Observer {
constructor(name) {
super(name);
}
call() {
console.log(`${this.name}汪汪叫`);
}
update() {
console.log(`观察者${this.name}做出响应`);
this.call();
}
}
// 创建观察目标:猫
const cat = new Subject();
// 创建观察者:老鼠和狗
const mouse = new MouseObserver("杰瑞");
const dog = new DogObserver("旺财");
// 将观察者添加到观察目标
cat.add(mouse);
cat.add(dog);
// 猫叫,通知所有观察者
cat.notify();
// 输出:
// 观察者杰瑞做出响应
// 杰瑞跑起来
// 观察者旺财做出响应
// 旺财汪汪叫
代码解析
- Subject 类负责管理观察者集合,并实现通知观察者的方法。
- Observer 类定义了观察者的基本接口,通过
update()
方法响应目标状态的变化。 - MouseObserver 和 DogObserver 是具体的观察者实现,分别定义了在目标变化时的不同响应行为。
- 目标对象调用
notify()
方法通知所有观察者更新。
模式的效果和应用
优点
- 解耦:观察目标和观察者之间通过抽象的耦合建立联系,允许它们独立地变化。
- 灵活性:允许动态增加或删除观察者,不影响目标对象。
- 广播通信:当目标对象状态变化时,所有观察者都能接收到通知。
- 遵循开闭原则:可以轻松添加新的观察者,而无需修改目标对象的代码。
缺点
- 性能消耗:如果观察者较多,通知所有观察者可能会产生性能瓶颈。
- 可能引发循环依赖:当观察者和目标对象相互依赖时,容易导致系统崩溃。
使用场景
- 依赖关系:当一个对象的状态发生变化时,需要通知其他对象进行更新。例如,用户界面中的事件响应、数据更新通知等场景。
- 事件驱动架构:观察者模式广泛应用于基于事件的架构设计,例如浏览器的 DOM 事件处理、Vue 或 React 中的组件更新等。
- 触发链:系统中多个对象需要在某个事件发生时进行处理,形成一个触发链。
观察者模式实际应用
1. MVC 架构
在 MVC 模式中,模型(Model)作为观察目标,视图(View)作为观察者。模型层的数据改变会自动通知视图层更新,这种通信机制正是观察者模式的应用。
2. DOM 事件监听
浏览器的事件监听机制(addEventListener
)是观察者模式的典型应用。事件源(如按钮)作为观察目标,监听器作为观察者,用户点击按钮时,触发所有注册的监听器回调函数。
document.getElementById('myButton').addEventListener('click', () => {
console.log('Button clicked');
});
3. Vue 的响应式系统
Vue 的响应式系统基于观察者模式实现。数据变化时,触发依赖的视图更新,视图组件作为观察者响应模型数据的变化。
总结
观察者模式通过定义一对多的依赖关系,使得目标对象的状态变化时可以通知所有相关的观察者。这种模式在需要解耦对象之间的依赖关系,或者需要事件驱动的场景中非常有用。它简化了代码结构,提高了系统的灵活性和可维护性,是很多框架和库中的核心设计模式。