Menu
CoddyTech

观察者模式

本课属于 Coddy Python 学习旅程的“面向对象编程”单元。第 47 课,共 64 课。

观察者模式会创建一种一对多关系:当一个对象(主题)的状态发生变化时,它会通知多个对象(观察者)。

这是一个用于管理观察者的简单 Subject 类:

class Subject:
    def __init__(self):
        self._observers = []
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def notify(self, message):
        for observer in self._observers:
            observer.update(message)

主题会保存一个观察者列表,并能一次性通知所有观察者。

创建简单的观察者类:

class EmailNotifier:
    def update(self, message):
        print(f"Email sent: {message}")

class SMSNotifier:
    def update(self, message):
        print(f"SMS sent: {message}")

每个观察者都有一个 update 方法,在收到通知时会调用它。

使用观察者模式:

# 创建主题对象
news = Subject()

# 创建观察者
email = EmailNotifier()
sms = SMSNotifier()

# 将观察者添加到主题对象
news.add_observer(email)
news.add_observer(sms)

# 通知所有观察者
news.notify("Breaking news: Python is awesome!")

创建一个股票价格跟踪器的实用示例:

class Stock:
    def __init__(self, symbol, price):
        self.symbol = symbol
        self._price = price
        self._observers = []
    
    def add_observer(self, observer):
        self._observers.append(observer)
    
    def set_price(self, price):
        self._price = price
        self.notify()
    
    def notify(self):
        for observer in self._observers:
            observer.update(self.symbol, self._price)

class Investor:
    def __init__(self, name):
        self.name = name
    
    def update(self, symbol, price):
        print(f"{self.name} notified: {symbol} is now ${price}")

# 使用股票追踪器
apple_stock = Stock("AAPL", 150)

investor1 = Investor("Alice")
investor2 = Investor("Bob")

apple_stock.add_observer(investor1)
apple_stock.add_observer(investor2)

apple_stock.set_price(155)  # 通知所有投资者

输出:

Email sent: Breaking news: Python is awesome!
SMS sent: Breaking news: Python is awesome!
Alice notified: AAPL is now $155
Bob notified: AAPL is now $155

要点:观察者模式可以让一个对象在发生变化时自动通知多个其他对象。主题对象维护一个观察者列表,并在需要时调用它们的 update 方法。这种模式适用于通知、事件系统,以及让应用程序的多个部分保持同步。

challenge icon

挑战

中等

通过创建一个天气监控系统来实现观察者模式。你需要在代码的指定区域创建两个类。

第 1 步:创建 WeatherStation 类

在注释指示的位置编写 WeatherStation 类。这个类应该:

  • 继承 Subject 类(使用 class WeatherStation(Subject):)
  • 初始化时:
    • 使用 super().__init__() 调用父类构造函数
    • 使用单下划线属性 self._temperature 将初始温度设为 0(这是 Python 对内部属性的约定)
  • 实现 set_temperature(self, temperature):
    • 更新内部温度属性
    • 调用 self.notify(self._temperature) 通知所有观察者
  • 实现 get_temperature(self):
    • 返回当前温度值

第 2 步:创建 WeatherDisplay 类

在注释指示的位置编写 WeatherDisplay 类。这个类应该:

  • 继承 Observer 类(使用 class WeatherDisplay(Observer):)
  • 初始化时:
    • 接收一个 name 参数
    • 将名称存储为 self.name
  • 实现 update(self, temperature):
    • 按照下方显示的准确格式打印温度更新消息

消息格式:

显示设备收到温度更新时,必须准确打印:

Display [name]: Current temperature is [temperature]C

使用示例:

# Create weather station and displays
station = WeatherStation()
phone_display = WeatherDisplay("Phone")
tablet_display = WeatherDisplay("Tablet")

# Attach displays to station
station.attach(phone_display)
station.attach(tablet_display)

# Update temperature - both displays will be notified
station.set_temperature(25.5)

# Output:
# Display Phone: Current temperature is 25.5C
# Display Tablet: Current temperature is 25.5C

重要说明:

  • attach() 和 detach() 方法已在 Subject 基类中实现,你不需要在 WeatherStation 类中实现或调用它们
  • 在上面的使用示例中,station.attach(phone_display) 是由使用你这个类的用户调用的,而不是在你的 WeatherStation 实现中调用的
  • 你的 WeatherStation 只需在温度变化时调用 self.notify(),其余工作由 Subject 基类处理
  • 请按照上面的说明,重点实现 WeatherStation 中要求的三个方法,以及 WeatherDisplay 中要求的两个方法

亲手试试

class Subject:
    def __init__(self):
        self._observers = []
    
    def attach(self, observer):
        self._observers.append(observer)
        
    def detach(self, observer):
        self._observers.remove(observer)
        
    def notify(self, data):
        for observer in self._observers:
            observer.update(data)
            
class Observer:
    def update(self, data):
        pass

# 在这里编写你的 WeatherStation 类

# 在这里编写你的 WeatherDisplay 类

quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Python 在线编译器