1. 一句话简介
观察者模式(Observer Pattern)是一种行为型的设计模式,它定义了一种类似“发布-订阅”的机制,使得一个对象(通常称为它主题、观察目标、发布方)的状态发生变化时,能够通知依赖该对象的其他对象(一般称它们为观察者、订阅方)并让她们更新各自的状态。
2. 用一个例子来理解观察者模式:学校整点报时
小明所在的学校有一个时钟(观察目标),每到整点时,它就会通知所有的学生(观察者)当前的时间,咱们可以使用观察者模式实现这个时钟通知系统。注意点:时间从 0 开始,并每隔一个小时更新一次。
2.1 UML图例
classDiagram
class Student {
-name: string
+update(message: Any): void
}
class IClock {
<<interface>>
+addStudent(student: Student): void
+removeStudent(student: Student): void
+notifyStudents(void): void
}
class HourlyClock {
-now: int
-students: List[Student]
+addStudent(student: Student): void
+removeStudent(student: Student): void
+notifyStudents(void): void
+tellTime(time: int): void
}
IClock <|.. HourlyClock
HourlyClock o-- Student
2.2 Python代码
卡码网设计模式习题集【设计模式专题之观察者模式】13. 时间观察者的题解:
from abc import ABC, abstractmethod
from typing import Any
class Student:
def __init__(self, name: str):
self.name = name
def update(self, message: Any):
print(f"{self.name} {message}")
class IClock(ABC):
@abstractmethod
def addStudent(self, student: Student):
raise NotImplemented
@abstractmethod
def removeStudent(self, student: Student):
raise NotImplemented
@abstractmethod
def notifyStudents(self):
raise NotImplemented
class HourlyClock(IClock):
def __init__(self):
self.now = 0
self.students: List[str] = []
def addStudent(self, student: Student):
self.students.append(student)
def removeStudent(self, student: Student):
self.students.remove(student)
def notifyStudents(self):
for stu in self.students:
stu.update(self.now)
def tellTime(self, time: int):
self.now = time
self.notifyStudents()
def client():
clock = HourlyClock()
n = int(input())
for _ in range(n):
name = input()
student = Student(name)
clock.addStudent(student)
m = int(input())
for i in range(1, m + 1):
clock.tellTime(i)
if __name__ == "__main__":
client()
3. 观察者模式的结构
观察者模式的主体是观察主题和观察者,但是一般有5个组成部分:
主题Subject, 一般会定义成一个接口,提供方法用于注册、删除和通知观察者,通常也包含一个状态,当状态发生改变时,通知所有的观察者。观察者Observer: 观察者也需要实现一个接口,包含一个更新方法,在接收主题通知时执行对应的操作。具体主题ConcreteSubject: 主题的具体实现, 维护一个观察者列表,包含了观察者的注册、删除和通知方法。具体观察者ConcreteObserver: 观察者接口的具体实现,每个具体观察者都注册到具体主题中,当主题状态变化并通知到具体观察者,具体观察者进行处理。客户端Client: 负责创建具体主题以及具体观察者,并调用具体主题的通知方法。
4. 观察者模式的优缺点以及使用场景
观察者模式是一种常用的设计模式,它具有许多优点,同时也有一些缺点。以下是观察者模式的优缺点以及适用场景:
优点:
-
松耦合:主题和观察者之间是松耦合的,主题只知道观察者接口,不需要知道具体的观察者,从而使系统更灵活、可扩展。
-
可重用性:主题和观察者可以被多次重复使用,不同的主题可以共享相同的观察者。
-
扩展性:可以在运行时动态地添加、删除观察者,而不需要修改主题的代码,从而实现了更好的扩展性。
-
灵活性:可以在不同的场景中使用观察者模式,例如在单线程或多线程环境下,同步或异步地通知观察者。
缺点:
-
可能引起内存泄漏:如果观察者没有被正确地移除,可能会导致内存泄漏问题,因为主题会保持对观察者的引用,即使观察者不再需要。
-
通知顺序不确定:观察者模式没有明确规定观察者被通知的顺序,这可能会导致观察者收到通知的顺序与期望不符。
-
可能导致性能问题:如果观察者数量较大,通知所有观察者可能会导致性能问题,特别是在多线程环境下。
使用场景:
-
事件处理:GUI 开发中的事件处理、用户界面更新等场景。
-
消息中间件:订阅/发布模式常用于消息中间件中,消息的发布者称为主题,消息的订阅者称为观察者。
-
状态变化通知:当一个对象的状态发生变化时,需要通知其他对象更新状态。
-
分布式系统:在分布式系统中,可以使用观察者模式来实现服务之间的通信和状态同步。
总的来说,观察者模式适用于一对多的依赖关系,当一个对象的改变需要通知其他多个对象时,观察者模式是一种有效的设计模式。