觀察者設計模式是最簡單的行爲型模式之一;行爲型模式,它主要關注的是對象的責任。它們用來處理對象之間的交互,以實現更大的功能。行爲型模式建議:對象之間應該能夠彼此交互,同時還應該是鬆散耦合的。
理解觀察者設計模式
在觀察者設計模式中,對象(主題)維護了一個依賴(觀察者)列表,以便主題可以使用觀察者定義的任何方法通知所有觀察者它所發生的變化。
在分佈式應用的世界中,多個服務通常是通過彼此交互來實現用戶想要實現的更大型的操作。服務可以執行多種操作,但是他們執行的操作會直接或很大程度上取決於與其交互的服務對象的狀態。
觀察者模式的主要目標如下:
1、它定義了對象之間一對多的依賴關係,從而使一個對象中的任何更改都將自動通知給其它依賴對象
2、他封裝了主題的核心組件
觀察者模式的應用場景:
1、在分佈式系統中實現事件服務
2、用作新聞機構的框架
3、股票市場也是觀察者模式的一個大型場景
Python代碼的實現:
class Subject(object):
def __init__(self):
self.__observer = []
def register(self, observer):
self.__observer.append(observer)
def notify_all(self, *args, **kwargs):
for observer in self.__observer:
observer.notify(self, *args, **kwargs)
class Observer1(object):
def __init__(self, subject):
subject.register(self)
def notify(self, subject, *args):
print(type(self).__name__, 'Got', args, 'From', subject)
class Observer2(object):
def __init__(self, subject):
subject.register(self)
def notify(self, subject, *args):
print(type(self).__name__, 'Got', args, 'From', subject)
subject = Subject()
observer1 = Observer1(subject)
observer2 = Observer2(subject)
subject.notify_all('notification')
觀察者模式三個主要角色:
1、主題(Subject):類Subject需要了解Observer。Subject類具有許多的方法,例如register()等,Observer可以通過這些方法註冊到Subject類中。因此,一個Subject可以處理多個Observe。
2、觀察者(Observer):它爲關注主題的對象定義了一個接口。它定義了Observer需要實現的各個方法,以便主題發生變化時能夠獲得相應的通知;
3、具體觀察者(ConcreteObserver):它用來保存應該與Subject的狀態保持一致的狀態。它實現了Observer接口以保持其狀態與主題中的變化相一致。
這個流程非常簡單。具體觀察者通過實現觀察者提供的接口向主題註冊自己。每當狀態發生變化時,該主題都會使用觀察者提供的通知方法來通告所有具體觀察者。
生活中的觀察者模式
我們將以新聞機構爲例來展示觀察者模式的生活中的場景。新聞機構通常從不同地點收集新聞,並將其發佈給訂閱者。下面利用Python來開發一個應用程序,實現上面的用例。
從主題開始,這裏的主題是新聞發佈者:
1、主題的行爲有NewsPublisher類表示
2、NewsPublisher提供了一個訂閱用戶使用的接口
3、attach()方法供觀察者(Observer)來註冊NewsPublisherObserver,detach()方法用於註銷
4、subscriber()方法返回已經使用Subject註冊所有訂閱用戶列表
5、notify_subscriber()方法可以用來遍歷已向NewsPublisher註冊的所有訂閱用戶
6、發佈者可以使用add_news()方法創建新的消息,get_news()用於返回最新消息,並且通知觀察者。
class NewsPublisher(object):
def __init__(self):
self.__subscribers = []
self.__latest_news = None
def attach(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 notify_subscribers(self):
for sub in self.__subscribers:
sub.update()
def add_news(self, news):
self.__latest_news = news
def get_news(self):
return "Got News:", self.__latest_news
現在我們討論觀察者(Observer)接口:
1、在這個例子中,Subscriber表示Observer,它是一個抽象的基類,代表其他ConcreteObserver;
2、Subscriber有一個update()方法,但是它需要由ConcreteObservers實現
3、update()方法是由ConcreteObserver實現的,這樣只要有新聞發佈時,它們都能夠得到Subject的相應通知
from abc import ABCMeta, abstractmethod
class Subscriber(object):
@abstractmethod
def update(self):
pass
下面試具體觀察者:
1、在本例中,我們有兩個主要觀察者,分別實現訂閱用戶接口的EmailSubscriber和SMSSubscriber
2、除了這兩個外,我們建立了另外一個觀察者AnyOtherObserver,它是用來演示Observers與Subject的鬆散耦合關係的
3、每個具體觀察者的__init__()方法都是使用attach()方法向NewsPublisher進行註冊
4、具體觀察者的update()方法由NewsPublisher在內部用來通知添加新的新聞
class SMSSubscriber(object):
def __init__(self, publisher):
self.publisher = publisher
self.publisher.attach(self)
def update(self):
print(type(self).__name__, self.publisher.get_news())
class EmailSubscriber(object):
def __init__(self, publisher):
self.publisher = publisher
self.publisher.attach(self)
def update(self):
print(type(self).__name__, self.publisher.get_news())
class AnyOtherSubscriber(object):
def __init__(self, publisher):
self.publisher = publisher
self.publisher.attach(self)
def update(self):
print(type(self).__name__, self.publisher.get_news())
以下代碼展示主題和觀察者之間的交互:
if __name__ == "__main__":
news_publisher = NewsPublisher()
for Subscribers in [SMSSubscriber, EmailSubscriber, AnyOtherSubscriber]:
Subscribers(news_publisher)
print("\nSubscribers:", news_publisher.subscribers())
news_publisher.add_news("地球爆炸了")
news_publisher.notify_subscribers()
print("\nDetached:", type(news_publisher.detach()).__name__)
print("\nSubscribers:", news_publisher.subscribers())
news_publisher.add_news("二二二二二")
news_publisher.notify_subscribers()