本文主要是介绍设计模式: 行为型之中观察者模式(19),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
观察者模式概述
- 观察者模式(Observer Pattern)是一种行为设计模式
- 它定义了对象之间的依赖关系,当一个对象(被称为主题或发布者)的状态改变时
- 所有依赖于它的对象(被称为观察者)都会得到通知并自动更新
观察者模式应用
// 定义观察者接口
interface Observer {update(data: any): void; // 更新方法,当主题状态改变时,观察者通过这个方法获取更新
}// 定义主题接口
interface Subject {attach(observer: Observer): void; // 注册观察者detach(observer: Observer): void; // 移除观察者notify(data: any): void; // 通知所有观察者状态改变
}// 创建一个具体主题类实现
class ConcreteSubject implements Subject {private observers: Observer[] = []; // 存储观察者集合private state: any;getState(): any {return this.state;}setState(newState: any): void {this.state = newState;this.notify(newState);}attach(observer: Observer): void {this.observers.push(observer);}detach(observer: Observer): void {const index = this.observers.indexOf(observer);if (index !== -1) {this.observers.splice(index, 1);}}notify(data: any): void {this.observers.forEach((observer) => observer.update(data));}
}// 创建一个具体观察者类实现
class ConcreteObserver implements Observer {private name: string;constructor(name: string) {this.name = name;}update(data: any): void {console.log(`${this.name} received the update: ${data}`);}
}// 使用示例
function main() {const subject = new ConcreteSubject();const observer1 = new ConcreteObserver("Observer 1");const observer2 = new ConcreteObserver("Observer 2");subject.attach(observer1);subject.attach(observer2);subject.setState("New State");
}main();
- 在这个例子中,
Observer
接口定义了观察者所需要实现的update
方法,当主题状态改变时,观察者通过这个方法获取更新信息 Subject
接口定义了主体类需要实现的方法,包括注册观察者(attach
)、移除观察者(detach
)和通知所有观察者(notify
)ConcreteSubject
类实现了Subject
接口,其中存储了观察者列表,并在状态改变时通过notify
方法通知所有观察者ConcreteObserver
类实现了Observer
接口,当接收到更新时,会打印出更新的信息- 在
main
函数中,我们创建了一个具体主题对象和两个具体观察者对象,将观察者对象注册到主题对象,然后更改主题状态,触发观察者对象的update
方法执行
观察者模式与发布订阅的区别和联系
- 观察者模式(Observer Pattern)和发布订阅模式(Publish-Subscribe Pattern)在设计理念上具有一定的相似性,都涉及到对象间的一对多依赖关系和事件通知机制,但它们在具体实现和适用场景上有所区别
- 观察者模式是经典的23种设计模式之一,属于行为型设计模式,它强调的是当对象状态改变时,能够自动通知其依赖的对象
- 发布订阅模式虽然在某些文献中也被看作是观察者模式的一个扩展或变体,但它并不是23种经典设计模式中明确列出的模式
- 发布订阅模式更倾向于在分布式系统和消息传递系统中应用,它通过引入消息中间件或者事件总线等机制进一步解耦了发布者和订阅者,使得它们可以异步处理消息,甚至在不同的进程中或服务器之间进行通信
1 )观察者模式(Observer Pattern)
- 定义
- 定义了一种一对多的依赖关系,当一个对象(Subject)的状态发生改变时
- 所有依赖于它的对象(Observer)都会得到通知并自动更新
- 特点
- 直接依赖:观察者(Observer)直接订阅目标(Subject)的状态变化
- 同步或异步:观察者模式既可以实现为同步也可以实现为异步,取决于具体实现
- 弱耦合:Subject只知道有观察者接口的存在,而不需要了解具体的观察者实现
- 应用场景:常应用于单个应用程序内部,如GUI编程中的事件处理、组件间通信等
2 )发布订阅模式(Publish-Subscribe Pattern)
- 定义
- 又称发布-订阅模式,引入了一个消息中心(Event Channel/Mediator)的概念,发布者(Publisher)发布事件到消息中心
- 订阅者(Subscriber)从消息中心订阅感兴趣的事件,两者并不直接相互依赖
- 特点
- 间接依赖:发布者和订阅者之间通过一个独立的媒介(消息中心)交换消息。
- 强烈异步:发布订阅模式通常采用异步的方式处理消息,更适合分布式环境和大规模系统的事件通信。
- 更高的解耦程度:发布者和订阅者完全不了解对方的存在,它们通过事件名称进行匹配。
- 应用场景:广泛应用于分布式系统、消息队列、跨进程/跨应用通信、微服务架构等。
3 )区别与联系
3.1 区别
- 关系模型:观察者模式是直接对象间的互动,而发布订阅模式通过第三方(消息中心)中转。
- 异步处理:观察者模式不一定异步,发布订阅模式通常是异步的。
- 适用范围:观察者模式常见于单一应用内,发布订阅模式更适合分布式和跨系统的事件处理。
3.2 联系
- 都是事件驱动:两者都基于事件通知机制,解决了对象间的通知和联动问题
- 解耦思想:都旨在减少对象间的直接耦合,使得系统更灵活,更易于扩展和维护。
4 )总结
- 观察者模式着重于对象级别的直接观察和通知
- 而发布订阅模式则更加强调通过消息渠道在更大范围内的事件传播和订阅
- 在实际应用中,观察者模式往往是发布订阅模式的一种实现方式,特别是在单体应用中
- 而在分布式系统中,发布订阅模式往往更为普遍,因为它能够更好地支持松耦合和异步通信
- 所以,观察者模式是23种设计模式中的一个正式成员,而发布订阅模式虽在理念上与之类似
- 但在实践中体现出了更广泛的适用性和更强的解耦能力,它是观察者模式在特定场景下的自然延伸和发展
发布订阅的应用
发布订阅模式(Publish-Subscribe Pattern)在TypeScript中的实践应用通常涉及事件分发和处理中心,也就是一个事件总线或事件通道
以下是一个基本的TypeScript实现
// 定义事件接口
interface Event {type: string;data?: any;
}// 定义订阅者接口
interface Subscriber {subscribe(eventType: string, callback: (event: Event) => void): void;unsubscribe(eventType: string, callback: (event: Event) => void): void;
}// 实现一个简单的发布订阅类
class PubSub implements Subscriber {private eventCallbacks: Map<string, ((event: Event) => void)[]> = new Map();// 订阅事件subscribe(eventType: string, callback: (event: Event) => void): void {let callbacks = this.eventCallbacks.get(eventType);if (!callbacks) {callbacks = [];this.eventCallbacks.set(eventType, callbacks);}callbacks.push(callback);}// 取消订阅事件unsubscribe(eventType: string, callback: (event: Event) => void): void {const callbacks = this.eventCallbacks.get(eventType);if (callbacks) {const index = callbacks.indexOf(callback);if (index > -1) {callbacks.splice(index, 1);}}}// 发布事件publish(event: Event): void {const callbacks = this.eventCallbacks.get(event.type);if (callbacks) {callbacks.forEach(cb => cb(event));}}
}// 使用示例
class UserComponent {private pubsub: PubSub;constructor(pubsub: PubSub) {this.pubsub = pubsub;this.initListeners();}initListeners() {this.pubsub.subscribe('user:login', this.onUserLogin.bind(this));}onUserLogin(event: Event) {console.log('User logged in:', event.data);}triggerUserLogin(user: any) {this.pubsub.publish({ type: 'user:login', data: user });}
}// 初始化PubSub实例和UserComponent
const pubsub = new PubSub();
const userComponent = new UserComponent(pubsub);// 触发用户登录事件
userComponent.triggerUserLogin({ username: 'example' });
- 在这个例子中:定义了
Event
接口描述事件的基本结构,包括事件类型和携带的数据 Subscriber
接口定义了订阅和取消订阅事件的方法PubSub
类实现了Subscriber
接口,维护了一个事件类型与回调函数数组的映射表,可以订阅、取消订阅事件以及发布事件UserComponent
类作为一个使用者,通过PubSub
类订阅特定事件,并在事件触发时执行相关操作。当用户登录时,通过triggerUserLogin
方法发布事件- 这样,通过发布订阅模式,我们可以轻松地在不同的组件间解耦事件的触发和响应逻辑,使得整个系统更加灵活和可扩展
关于浏览器UI点击事件
-
UI上的按钮点击事件通常更接近于观察者模式
-
在观察者模式中,一个对象(称为主题或可观察对象)维护一个依赖于它的对象列表(称为观察者),当主题的状态发生变化时,它会通知所有的观察者
-
具体到UI上的按钮点击事件,按钮本身可以被看作是可观察对象,而点击事件的监听器或回调函数则是观察者
-
当按钮被点击时,它的状态发生了变化(从未被点击到被点击),此时它会通知所有注册了点击事件的监听器或回调函数,这些监听器或回调函数随后会执行相应的操作
-
虽然发布订阅模式与观察者模式在概念上有相似之处,但在典型的发布订阅模式中,消息是通过一个中央的消息代理(或称为发布者/订阅者管理器)进行传递的
-
发布者将消息发布到消息代理,而订阅者则从消息代理中订阅它们感兴趣的消息。这种模式在分布式系统或大型应用中更为常见,因为它可以实现更高级别的解耦和灵活性。
-
然而,在UI按钮点击事件的上下文中,通常没有这样一个中央的消息代理
-
按钮直接与其监听器或回调函数进行交互,因此更符合观察者模式的直接交互特性
-
总结来说,UI上的按钮点击事件通常被视为观察者模式的一个实例,尽管在某些情况下,也可以将其设计为实现发布订阅模式,但这通常不是最常见的做法
这篇关于设计模式: 行为型之中观察者模式(19)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!