事半功倍?别再说你不懂设计模式里的观察者模式!
2022-11-19 00:30:23
观察者模式与发布订阅模式:掌握编程界的多人协作
在软件开发中,你是否遇到过这样的情况:当一个对象的状态发生改变时,你需要其他对象做出相应的反应?传统的做法是让这些对象紧密耦合在一起,当一个对象发生改变时,其他对象就会直接收到通知。然而,这种方法存在一个重大的缺陷:随着系统的复杂性增加,对象之间的耦合度也会变得很高,维护起来极其困难。
观察者模式 就是为了解决这个问题而诞生的。它是一种设计模式,允许对象之间松散耦合。当一个对象发生改变时,它只需要通知它的观察者,观察者再做出相应的反应。这样一来,对象之间的耦合度就大大降低,系统的可维护性也得到了提升。
如何理解观察者模式
想象一下你在一家餐馆里,作为顾客的你是一位观察者,而服务员是你要观察的对象。当你想要点菜时,你不会直接走到厨房里,而是告诉服务员你的需求。服务员再把你的需求传达给厨房,厨房收到你的订单后就会开始准备菜品。这样一来,你作为顾客只需要关注服务员,而不用关心厨房的具体运作细节。这就是观察者模式的原理。
代码示例:观察者模式
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self):
for observer in self._observers:
observer.update()
class ConcreteSubject(Subject):
def __init__(self, state):
super().__init__()
self._state = state
@property
def state(self):
return self._state
@state.setter
def state(self, new_state):
self._state = new_state
self.notify()
class Observer:
def update(self):
pass
class ConcreteObserverA(Observer):
def update(self):
print("ObserverA notified, state is:", subject.state)
class ConcreteObserverB(Observer):
def update(self):
print("ObserverB notified, state is:", subject.state)
if __name__ == "__main__":
subject = ConcreteSubject(0)
observer1 = ConcreteObserverA()
observer2 = ConcreteObserverB()
subject.attach(observer1)
subject.attach(observer2)
subject.state = 1
subject.state = 2
发布订阅模式
发布订阅模式 与观察者模式非常相似,但也有其独特之处。在观察者模式中,观察者必须知道被观察者的身份,而在发布订阅模式中,订阅者并不知道发布者的身份。发布者只需将消息发布到消息总线上,订阅者只需要订阅消息总线上的消息,就可以接收消息。
如何理解发布订阅模式
发布订阅模式就像一个广播电台。电台(发布者)会不断播放音乐(消息),而听众(订阅者)可以随时调到这个电台(订阅消息总线)来收听音乐(接收消息)。电台并不知道每个听众的身份,而听众也只需要知道电台的频率,并不需要知道电台的具体位置和运作方式。
代码示例:发布订阅模式
import asyncio
class Publisher:
def __init__(self):
self.subscribers = []
def subscribe(self, subscriber):
self.subscribers.append(subscriber)
def publish(self, message):
for subscriber in self.subscribers:
subscriber.receive(message)
class Subscriber:
def __init__(self, name):
self.name = name
async def receive(self, message):
print(f"Subscriber {self.name} received message: {message}")
async def main():
publisher = Publisher()
subscriber1 = Subscriber("Sub1")
subscriber2 = Subscriber("Sub2")
publisher.subscribe(subscriber1)
publisher.subscribe(subscriber2)
publisher.publish("Hello, world!")
asyncio.run(main())
观察者模式与发布订阅模式的区别
虽然观察者模式和发布订阅模式都实现了对象之间的松散耦合,但它们之间还是存在一些区别:
- 在观察者模式中,观察者必须知道被观察者的身份,而在发布订阅模式中,订阅者并不知道发布者的身份。
- 在观察者模式中,被观察者必须知道所有的观察者,而在发布订阅模式中,发布者不需要知道所有的订阅者。
- 在观察者模式中,观察者可以随时添加或删除,而在发布订阅模式中,订阅者只能在订阅消息总线时添加,不能在订阅后删除。
观察者模式的应用场景
观察者模式的应用场景非常广泛,包括:
- 图形用户界面(GUI):当用户操作一个控件时,其他控件需要做出相应的反应。
- 事件处理系统:当一个事件发生时,需要通知相关对象。
- 分布式系统:当一个节点发生故障时,需要通知其他节点。
发布订阅模式的应用场景
发布订阅模式也有着广泛的应用场景,包括:
- 前端和后端的通信。
- 微服务架构中的服务发现和注册。
- 事件总线。
常见问题解答
1. 观察者模式和发布订阅模式哪个更好?
这两种模式各有优缺点,具体选择哪一种取决于具体的应用场景。
2. 如何选择合适的消息总线?
有很多不同的消息总线可用,比如 RabbitMQ、Kafka 和 ZeroMQ。选择合适的消息总线取决于系统的具体需求,如吞吐量、延迟和可靠性要求。
3. 如何处理消息丢失或延迟?
可以通过使用可靠的消息传递机制(如事务或幂等操作)来处理消息丢失或延迟。
4. 如何扩展发布订阅系统以处理大规模数据?
可以使用分片或分区技术将大型消息总线拆分为多个较小的部分。
5. 如何保护消息免受未经授权的访问?
可以通过使用加密和身份验证机制来保护消息免受未经授权的访问。