Python 程序语言设计模式思路-行为型模式:观察者模式:定义对象之间的一对多依赖关系及利用观察者模式实现日志系统和股票价格观察

Python 行为型模式:观察者模式:定义对象之间的一对多依赖关系

公众号:人生只不过是一场投资

引言

在软件开发中,设计模式是一套被反复使用、经过分类和总结的代码设计经验。被广泛用于解决常见的问题。在 Python 脚本设计中,创建对象的方式多种多样,设计模式提供了多种有效的解决方案。观察者模式(Observer Pattern)是一种行为型设计模式,旨在定义对象之间的一对多依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。观察者模式特别适用于事件驱动的系统,通过松耦合的方式实现对象之间的通信。本文将探讨Python中的观察者模式,介绍其应用领域,提供代码实例及详解,并分析其优缺点,最终得出结论。

应用领域

观察者模式在以下几种场景中有广泛的应用:

  1. 事件处理系统:在图形用户界面(GUI)和实时系统中,观察者模式常用于事件处理机制,监听用户的操作并作出相应的反应。
  2. 数据变化通知:在数据模型与视图分离的架构中,当数据发生变化时,通过观察者模式通知视图更新显示。
  3. 消息广播系统:在发布-订阅(Publish-Subscribe)系统中,观察者模式用于实现消息的广播和接收。
  4. 日志系统:在需要记录系统行为的日志系统中,观察者模式可以实时通知日志记录器记录相关信息。

示例一

from abc import ABC, abstractmethod
from typing import List

# 抽象主题类
class Subject(ABC):
    """
    主题接口,定义了添加、删除观察者以及通知观察者的方法
    """
    def __init__(self):
        self._observers: List[Observer] = []  # 存储观察者对象的列表

    def attach(self, observer: 'Observer') -> None:
        """
        添加观察者
        """
        self._observers.append(observer)

    def detach(self, observer: 'Observer') -> None:
        """
        删除观察者
        """
        self._observers.remove(observer)

    def notify(self) -> None:
        """
        通知所有观察者
        """
        for observer in self._observers:
            observer.update(self)

# 抽象观察者类
class Observer(ABC):
    """
    观察者接口,定义了更新方法
    """
    @abstractmethod
    def update(self, subject: Subject) -> None:
        """
        接收来自主题的通知,并进行相应的处理
        """
        pass

# 具体主题类
class Data(Subject):
    """
    具体主题类,存储数据并管理观察者
    """
    def __init__(self, value: int):
        super().__init__()
        self._value = value

    @property
    def value(self) -> int:
        return self._value

    @value.setter
    def value(self, new_value: int) -> None:
        """
        当数据发生变化时,通知所有观察者
        """
        self._value = new_value
        self.notify()

# 具体观察者类
class HexObserver(Observer):
    """
    十六进制观察者,将数据转换为十六进制并打印
    """
    def update(self, subject: Data) -> None:
        print(f"Hex Observer: {hex(subject.value)}")

# 具体观察者类
class BinaryObserver(Observer):
    """
    二进制观察者,将数据转换为二进制并打印
    """
    def update(self, subject: Data) -> None:
        print(f"Binary Observer: {bin(subject.value)}")

# 实例化主题和观察者
data = Data(10)
hex_observer = HexObserver()
binary_observer = BinaryObserver()

# 将观察者添加到主题
data.attach(hex_observer)
data.attach(binary_observer)

# 修改数据,触发通知
data.value = 15

# 输出:
Hex Observer: 0xf
Binary Observer: 0b1111

代码解释:

  1. 抽象类: SubjectObserver 是抽象类,定义了主题和观察者的基本接口。
  2. 具体类: Data 是具体的主题类,存储数据并管理观察者;HexObserverBinaryObserver 是具体的观察者类,分别将数据转换为十六进制和二进制并打印。
  3. 观察者模式: 当 Data 对象的数据发生变化时,会调用 notify() 方法通知所有观察者。观察者接收到通知后,会调用 update() 方法进行相应的处理。

这个案例展示了如何使用 Python 的观察者设计模式实现数据变化通知。当 Data 对象的数据发生变化时,HexObserverBinaryObserver 会自动收到通知并进行相应的处理。

示例二

我们以一个股票市场系统为例,演示观察者模式的实现。该系统包含股票数据和多个投资者,当股票价格更新时,所有投资者都会收到通知并做出相应决策。

from abc import ABC, abstractmethod

# 定义一个主题接口:

class Subject(ABC):
    @abstractmethod
    def register_observer(self, observer):
        pass

    @abstractmethod
    def remove_observer(self, observer):
        pass

    @abstractmethod
    def notify_observers(self):
        pass


# 定义一个观察者接口:
class Observer(ABC):
    @abstractmethod
    def update(self, temperature, humidity, pressure):
        pass


# 定义投资者类,实现更新方法:

class Investor(Observer):
    def __init__(self, name):
        self.name = name

    def update(self, stock, price):
        print(f"{self.name} notified: {stock} price changed to {price}")

# 定义股票数据类,当价格变化时通知所有投资者:

class StockData(Subject):
    def __init__(self):
        self.observers = {}
        self.prices = {}

    def register_observer(self, stock, observer):
        if stock not in self.observers:
            self.observers[stock] = []
        self.observers[stock].append(observer)

    def remove_observer(self, stock, observer):
        if stock in self.observers:
            self.observers[stock].remove(observer)

    def notify_observers(self, stock):
        for observer in self.observers.get(stock, []):
            observer.update(stock, self.prices[stock])

    def set_price(self, stock, price):
        self.prices[stock] = price
        self.notify_observers(stock)

# 通过具体的股票数据和投资者实现通知机制:

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

stock_data.register_observer("AAPL", investor1)
stock_data.register_observer("GOOGL", investor2)

stock_data.set_price("AAPL", 150)
stock_data.set_price("GOOGL", 2800)

# 运行结果:
Alice notified: AAPL price changed to 150
Bob notified: GOOGL price changed to 2800

优点

  1. 解耦:观察者模式通过将观察者和被观察对象分离,降低了代码的耦合度,提高了系统的可维护性。
  2. 动态更新:当被观察对象的状态发生变化时,所有观察者都能及时得到通知并更新,实现了实时响应。
  3. 灵活性:观察者模式允许动态添加和移除观察者,增强了系统的灵活性和扩展性。
  4. 分布式通信:观察者模式适用于分布式系统中的事件通知和消息传递,简化了跨节点的通信。

缺点

  1. 通知延迟:如果观察者数量较多,通知的传播可能会导致一定的延迟,影响系统的实时性。
  2. 内存泄漏:如果未正确管理观察者的注册和注销,可能会导致内存泄漏问题,增加系统的资源消耗。
  3. 复杂性增加:在某些情况下,过多的观察者和通知机制可能会增加系统的复杂性,难以理解和维护。

结论

观察者模式在定义对象之间的一对多依赖关系方面具有显著的优势,尤其在事件处理系统、数据变化通知、消息广播系统和日志系统等场景中表现出色。尽管观察者模式存在通知延迟和内存泄漏等缺点,但其带来的解耦性和灵活性使其在实际开发中非常有价值。在实际应用中,应根据具体需求权衡利弊,合理使用观察者模式,以充分发挥其优势,避免其不足对系统造成影响。通过合适的设计和实现,观察者模式在Python应用中可以有效提高系统的实时性和可维护性。

利用观察者模式实现日志系统

from abc import ABC, abstractmethod
import logging

# 设置日志系统
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class Subject:
    """
    主题类,负责维护观察者列表并通知观察者更新
    """

    def __init__(self):
        self._observers = []
        self.state = None

    def attach(self, observer):
        """添加观察者"""
        logging.info(f"Attaching observer: {observer}")
        self._observers.append(observer)

    def detach(self, observer):
        """移除观察者"""
        logging.info(f"Detaching observer: {observer}")
        if observer in self._observers:
            self._observers.remove(observer)

    def notify(self):
        """通知所有观察者进行更新"""
        logging.info("Notifying observers...")
        for observer in self._observers:
            observer.update(self)

    def change_state(self, new_state):
        """改变主题状态并通知观察者"""
        self.state = new_state
        logging.info(f"State changed to: {new_state}")
        self.notify()


class Observer(ABC):
    """
    观察者抽象基类,定义观察者接口
    """

    @abstractmethod
    def update(self, subject):
        """观察者更新方法,由具体观察者实现"""
        pass


class ConcreteObserverA(Observer):
    """具体观察者A"""

    def update(self, subject):
        logging.info(f"ConcreteObserverA: Reacted to the change. New state is: {subject.state}")


class ConcreteObserverB(Observer):
    """具体观察者B"""

    def update(self, subject):
        logging.info(f"ConcreteObserverB: Reacted to the change. New state is: {subject.state}")


if __name__ == "__main__":
    # 创建主题
    subject = Subject()

    # 创建观察者
    observer_a = ConcreteObserverA()
    observer_b = ConcreteObserverB()

    # 添加观察者
    subject.attach(observer_a)
    subject.attach(observer_b)

    # 改变主题状态并通知观察者
    subject.change_state("State 1")

    # 移除观察者
    subject.detach(observer_a)

    # 再次改变主题状态并通知观察者
    subject.change_state("State 2")

代码解释:

  1. 日志记录: 使用 logging 模块记录每个操作,例如添加/移除观察者、状态改变和通知。
  2. Subject 类:
    • 维护观察者列表 _observers
    • attachdetach 方法用于添加和移除观察者。
    • notify 方法遍历观察者列表并调用每个观察者的 update 方法。
    • change_state 方法改变主题状态并调用 notify 方法通知观察者。
  3. Observer 抽象基类:
    • 定义 update 方法作为观察者接口。
  4. ConcreteObserverA 和 ConcreteObserverB:
    • 具体观察者类,实现 update 方法以响应主题状态改变。

运行结果:

控制台会输出以下日志信息:

2023-10-26 16:51:00,345 - INFO - Attaching observer: <__main__.ConcreteObserverA object at 0x7f93644d3460>
2023-10-26 16:51:00,345 - INFO - Attaching observer: <__main__.ConcreteObserverB object at 0x7f93644d3490>
2023-10-26 16:51:00,345 - INFO - State changed to: State 1
2023-10-26 16:51:00,346 - INFO - Notifying observers...
2023-10-26 16:51:00,346 - INFO - ConcreteObserverA: Reacted to the change. New state is: State 1
2023-10-26 16:51:00,346 - INFO - ConcreteObserverB: Reacted to the change. New state is: State 1
2023-10-26 16:51:00,346 - INFO - Detaching observer: <__main__.ConcreteObserverA object at 0x7f93644d3460>
2023-10-26 16:51:00,347 - INFO - State changed to: State 2
2023-10-26 16:51:00,347 - INFO - Notifying observers...
2023-10-26 16:51:00,347 - INFO - ConcreteObserverB: Reacted to the change. New state is: State 2

这表明观察者模式正常工作,观察者会响应主题状态的变化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ょ镜花う水月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值