一、行为型模式简介
1. 创建型模式的工作原理是基于对象的创建机制的。由于这些模式隔离了对象的创建细节,所以使得代码能够与要创建的对象的类型相互独立。
2. 结构型模式用于设计对象和类的结构,从而使他们可以相互协作以获得更大的结构。重点在于简化结构以及识别类和对象之间的关系。
3. 行为型模式重点关注的是对象的责任。他们用来处理对象之间的交互,以实现更大的功能。行为型模式:对象之间应该能够彼此交互,同时还应该是松散耦合的。
二、理解观察者设计模式
目标:
1. 它定义了对象之间的一对多的依赖关系,从而使得一个对象中的任何更改都将自动通知其他依赖对象。
2. 它封装了主题的核心组件。
使用场景:
1. 在分布式系统中实现事件服务。
2. 用作新闻机构的框架。
3. 股票市场。
UML图:
1. 主题(Subject):类Subject需要了解Observer。Subject类具有许多方法,诸如register()和deregister()等,Observer可以通过这些方法注册到Subject类中。因此,一个Subject可以处理多个Observer。
2. 观察者(Observer):它为关注主题的对象定义了一个接口。它定义了Observer需要实现的各个方法,以便在主题发生变化时能够获得相应的通知。
3. 具体观察者(ConcreteObserver):它用来保存应该与Subject的状态保持一致。它实现了Observer接口以保持其状态与主题中的变化相一致。
三、现实世界中的观察者模式
新闻机构示例代码:
# -*- coding: UTF-8 -*-
from abc import ABCMeta, abstractmethod
# 订新闻的接口(主题)
class NewsPublisher:
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):
@abstractmethod
def update(self):
pass
# SMS用户(实际观察者)
class SMSSubscriber:
def __init__(self,publisher):
self.publisher = publisher
self.publisher.attch(self)
def update(self):
print(type(self).__name__, self.publisher.getNews())
# 邮件用户(实际观察者)
class EmailSubscriber:
def __init__(self,publisher):
self.publisher = publisher
self.publisher.attch(self)
def update(self):
print(type(self).__name__, self.publisher.getNews())
# 其他用户(实际观察者)
class AnyOtherSubscriber:
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) # 观察者,向主题订阅
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() # 发布消息
四、观察者通知方式
1. 拉模型
1.1 每当发生变化时,主题都会向所有已注册的观察者进行广播。
1.2 出现变化时,观察者负责获取相应变化情况,或者从订户那里拉去数据。
1.3 拉模型效率较低,因为它涉及两个步骤。第一步,主题通知观察者,第二部,观察者从主题那里提取所需的数据。
2. 推模型
2.1 变化由主题推送到观察者。
2.2 在拉模型中,主题可以向观察者发送详细的信息。当主题发送大量观察者永不到的数据时,会使相应时间过长。
2.3 由于只从主题发送所需的数据,所以能够提高性能。
五、松耦合与观察者模式
1.松耦合架构特性:
1.1 降低一个元素内发生的更改可能对其他元素产生意外影响的风险。
1.2 它使得测试、维护和故障排除工作更加简单。
1.3 系统可以轻松地分解为可定义的元素。
2.观察者模式:
2.1 主题对观察者唯一了解的就是实现一个特定的接口。同时不需要了解具体的观察者类。
2.2 可以随时添加任意的新观察者。
2.3 添加新观察者,根本不需要修改主题。
2.4 观察者和主题没有绑定在一起,可以彼此独立使用。如果有需要,观察者可以在任何地方重用。
2.5 观察者中的变化不会互相影响。
六、观察者模式:优点和缺点
1. 优点:
1.1 它使得彼此交互的对象之间保持松耦合。
1.2 它使得我们可以在无需对主题或观察者进行任何修改的情况下,高效地发送数据到其他对象。
1.3 可以随时添加/删除观察者。
2. 缺点:
2.1 观察者接口必须由具体观察者实现,而这涉及继承。无法进行组合,因为观察者接口可以实例化。
2.2 如何实现不当的华,观察者可能会增加复杂性,并且导致性能降低。
2.3 通知可能不可靠,并且导致竞争条件或不一致。
七、常见问答
1. 可能存在多个主题和观察者吗?
可能。这种情况,若要正常工作:需要通知观察者哪些主题发生了变化以及各个主题中发生了哪些变化。
2. 谁负责触发更新?
观察者模式可以在推模型和拉模型中工作。通常发生更新时,主题会触发更新方法,但有时可以根据应用程序的需要,观察者也是可以触发通知的。然而,需要注意的是频率不应该太高,否则则可能导致性能下降,特别是当主题的更新不太频繁时。
3. 主题或观察者可以在任何其他用例中访问吗?
都可以独立使用
本系列项目代码地址:Python-design-pattern