一. 行为型模式
创建型模式基于对象的创建机制, 隔离了对象的创建细节, 使代码能够与要创建的对象的类型相互独立
结构型模式用于设计对象和类的结构, 使它们可以相互协作以获得更大的结构
行为型模式主要关注对象的责任, 用来处理对象之间的交互, 以实现更大的功能
二. 理解观察者模式
观察者模式是一种行为型模式, 在观察者模式当中, 主题维护了一个依赖 (观察者) 列表, 以便主题可以使用观察者定义的任何方法通知所有观察者它所发生的变化.
我们使用 UML 图来理解
Observer 为观察者定义了一个接口, 里边定义了观察者获得通知的方法, ConcreteObserver(具体观察者)实现这些接口, 并与主题创建相关联系, Subject 主题存储所有注册的观察者, 并向所有观察者发送新消息.
简单理解: 观察者模式即为许多对象等待着某个主题对象的新消息, 当主题对象有了新消息的时候, 它就会通知所有的观察着它的对象, 就像是很多的用户都订阅了一位新闻发布者, 当新闻发布者发布了一个新的新闻后, 他就会通知它的所有订阅者, 就像是手机上一些应用的通知栏通知.
三. python 实现观察者模式
观察者模式有两种通知方式, 拉模型和推模型
1. 拉模型
- from abc import ABCMeta,abstractmethod
- class NewsPublisher: #subject
- def __init__(self):
- self.__subscribers = []
- self.__latestNews = None
- def attach(self,subscriber):
- self.__subscribers.append(subscriber)
- def detach(self):
- return self.__subscribers.pop()
- 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 ConcreteSubscriber1: #ConcreteObserver
- def __init__(self,publisher):
- self.publisher=publisher
- self.publisher.attach(self)
- def update(self):
- print(type(self).__name__,self.publisher.getNews())
- class ConcreteSubscriber2:
- def __init__(self, publisher):
- self.publisher = publisher
- self.publisher.attach(self)
- def update(self):
- print(type(self).__name__, self.publisher.getNews())
- news_publisher = NewsPublisher()
- for Subscribers in [ConcreteSubscriber1,ConcreteSubscriber2]: #创建观察者对象
- Subscribers(news_publisher)
- news_publisher.addNews('HELLO WORLD')
- news_publisher.notifySubscribers()
- news_publisher.detach()
- news_publisher.addNews('SECOND NEWS')
- news_publisher.notifySubscribers()
- '''
- ConcreteSubscriber1 Got News:HELLO WORLD
- ConcreteSubscriber2 Got News:HELLO WORLD
- ConcreteSubscriber1 Got News:SECOND NEWS
- '''
上面的代码应该很容易就读懂了, 但是拉模型在这里是什么意思呢, 先看一下拉模型的含义:
每当发生变化时, 主题都会向所有已经注册的观察者进行广播
出现变化后, 观察者负责获取相应的变化情况, 或者从订户那里拉去数据
拉模型涉及两个步骤, 主题通知观察者, 观察者从主题那里提取数据
具体到代码中, 主题通知观察者步骤即为 news_publisher.notifySubscribers()中调用所有观察者的 update 方法, 这里的 update 方法没有参数, 观察者从主题那里提取数据步骤即为具体观察者的 update 方法中又调用 self.publisher.getNews()来获得数据
2. 推模型
了解了拉模型, 推模型就很容易理解了, 它与拉模型的不同之处就在于它一步到位, 主题直接发送信息到观察者, 代码只需将拉模型的稍微改动即可:
- from abc import ABCMeta,abstractmethod
- class NewsPublisher: #subject
- def __init__(self):
- self.__subscribers = []
- self.__latestNews = None
- def attach(self,subscriber):
- self.__subscribers.append(subscriber)
- def detach(self):
- return self.__subscribers.pop()
- def notifySubscribers(self):
- for sub in self.__subscribers:
- sub.update(self.__latestNews)
- 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 ConcreteSubscriber1: #ConcreteObserver
- def __init__(self,publisher):
- self.publisher=publisher
- self.publisher.attach(self)
- def update(self,news):
- print(type(self).__name__,news)
- class ConcreteSubscriber2:
- def __init__(self, publisher):
- self.publisher = publisher
- self.publisher.attach(self)
- def update(self,news):
- print(type(self).__name__, news)
- news_publisher = NewsPublisher()
- for Subscribers in [ConcreteSubscriber1,ConcreteSubscriber2]: #创建观察者对象
- Subscribers(news_publisher)
- news_publisher.addNews('HELLO WORLD')
- news_publisher.notifySubscribers()
- news_publisher.detach()
- news_publisher.addNews('SECOND NEWS')
- news_publisher.notifySubscribers()
- '''
- ConcreteSubscriber1 HELLO WORLD
- ConcreteSubscriber2 HELLO WORLD
- ConcreteSubscriber1 SECOND NEWS
- '''
这里只将 update 函数添加了传递的数据参数, 并在 notifySubscribers 函数中传递了参数.
这种方式只有一个步骤就是主题发送数据, 所以能够提高性能, 但缺点就是观察者会获得可能自己不需要的数据, 当有大量数据观察者都用不到的话就会很浪费了, 使响应时间过长. 两种方式各有利弊
四. 观察者模式的优缺点
优点:
它使彼此交互的对象保持松耦合
当需要添加其他对象时, 无需对主题和观察者做任何修改
可以随时添加和删除观察者
缺点:
实现不当可能会增加复杂性, 导致性能降低
通知有时是不可靠的, 并导致竞争条件或不一致性
来源: https://www.cnblogs.com/sfencs-hcy/p/10056376.html