定义对象间具有一对多的依赖关系,使得當主对象有任何變化時則發出通知給其它依赖对象,此模式可對關注的核心主题對象(*即依賴對象)進行再次封装。常見之應用场景如下:
- 分布式系统中实现事件之服务。
- 新闻机构的框架。
- 股票市场。
UML图:
- 主题Subject類:主要負責引入ConcreteObserver具体類作為關注對象,故須提供注册/注銷方法以可對ConcreteObserver具体類作管理,另外還須提供通知方法以讓主题Subject類發生變化時可發出通知給所關注對象。
- 观察者Observer抽象類:定义具体覌察者ConcreteObserver需要实现的接口,以便在接獲主题Subject類发出通知时能够執行相应的動作。
- 观察者ConcreteObserver具体類:实现观察者Observer抽象類定義之接口。
示例:新闻机构
# -*- coding: UTF-8 -*-
from abc import ABCMeta, abstractmethod
class NewsPublisher: #主题Subject類
def __init__(self):
self.__subscribers = []
self.__latestNews = None
def attch(self,subscriber): #注册
self.__subscribers.append(subscriber)
def detach(self): #注销
return self.__subscribers.pop()
def subscribers(self): #關注之订閱者
return [type(x).__name__ for x in self.__subscribers]
def notifySubscribers(self): #通知
for sub in self.__subscribers:
sub.update()
def addNews(self, news): #加入最新消息
self.__latestNews = news
def getNews(self): #取得最新消息
return "Got News:",self.__latestNews
class Subscriber(metaclass=ABCMeta): #观察者Observer抽象類,此示例是對用户而言
@abstractmethod
def update(self):
pass
class SMSSubscriber(Subscriber): #观察者ConcreteObserver具体類--SMS用户
def __init__(self,publisher): #主動向主題Subject類作訂閱
self.publisher = publisher
self.publisher.attch(self)
def update(self):
print(type(self).__name__, self.publisher.getNews())
class EmailSubscriber(Subscriber): #观察者ConcreteObserver具体類--邮件用户
def __init__(self,publisher):
self.publisher = publisher
self.publisher.attch(self)
def update(self):
print(type(self).__name__, self.publisher.getNews())
class AnyOtherSubscriber(Subscriber): #观察者ConcreteObserver具体類--其他用户
def __init__(self,publisher):
self.publisher = publisher
self.publisher.attch(self)
def update(self):
print(type(self).__name__, self.publisher.getNews())
實際業務場景如下:
if __name__ == "__main__":
news_publisher = NewsPublisher()
for Subscribers in [SMSSubscriber,EmailSubscriber,AnyOtherSubscriber]:
Subscribers(news_publisher) #观察者ConcreteObserver具体類向主题Subject類作订阅
print("\nSubscribers:",news_publisher.subscribers()) #查看订阅列表
news_publisher.addNews("Hello World!") #加入新消息(*第一則)
news_publisher.notifySubscribers() #发出通知
print("\nDetached:",type(news_publisher.detach()).__name__) #删除订阅者(*此指最後者)
print("\nSubscribers:",news_publisher.subscribers()) #查看订阅列表
news_publisher.addNews("My second news") #加入新消息(*第二則)
news_publisher.notifySubscribers() #发出通知
輸出:
Subscribers: ['SMSSubscriber', 'EmailSubscriber', 'AnyOtherSubscriber']
SMSSubscriber ('Got News:', 'Hello World!')
EmailSubscriber ('Got News:', 'Hello World!')
AnyOtherSubscriber ('Got News:', 'Hello World!')
Detached: AnyOtherSubscriber
Subscribers: ['SMSSubscriber', 'EmailSubscriber']
SMSSubscriber ('Got News:', 'My second news')
EmailSubscriber ('Got News:', 'My second news')
四、观察者通知類型
- 拉模型
1.1 每当发生变化时,主题都会向所有已注册的观察者进行广播,观察者负责获取相应变化情况或者从主題那里去拉数据。。
1.2 拉模型效率较低,因为它涉及两个步骤。第一步:主题通知观察者,第二部:观察者从主题那里提取所需的数据。
2. 推模型
2.1由主题推送变化到观察者,即由主题向观察者推送详细的信息,但当主题发送大量观察者用不到的数据时,仍会使相应时间过长。。
2.2由于从主题发送所需的数据,所以能够提高性能。