观察者模式

代码实现(Python版本):

cpp 复制代码
class Observer:
   def update(self, message):
       raise NotImplementedError("You should implement this method.")


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, message):
       """通知所有观察者"""
       for observer in self._observers:
           observer.update(message)


class ConcreteSubject(Subject):
   def __init__(self):
       super().__init__()
       self._state = None

   def change_state(self, new_state):
       """改变状态并通知观察者"""
       self._state = new_state
       print(f"Subject state changed to: {self._state}")
       self.notify(self._state)


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

   def update(self, message):
       """接收通知并处理"""
       print(f"Observer {self._name} received message: {message}")


if __name__ == "__main__":
   subject = ConcreteSubject()

   observer1 = ConcreteObserver("Observer 1")
   observer2 = ConcreteObserver("Observer 2")

   subject.attach(observer1)  # 观察者1注册到主题
   subject.attach(observer2)  # 观察者2注册到主题

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

   subject.detach(observer1)  # 移除观察者1
   subject.change_state("State 3")  # 观察者2仍然会收到通知

当您运行这个程序时,您将看到观察者接收到主题状态变化的通知,具体输出如下:

cpp 复制代码
Subject state changed to: State 1
Observer Observer 1 received message: State 1
Observer Observer 2 received message: State 1
Subject state changed to: State 2
Observer Observer 1 received message: State 2
Observer Observer 2 received message: State 2
Subject state changed to: State 3
Observer Observer 2 received message: State 3

观察者模式又叫发布/订阅模式(Publish/Subscribe)模式。

监听设计模式还可以分为推模式和拉模式。

下面是使用Python实现监听设计模式(观察者模式)的推模式和拉模式的示例代码。我们将定义一个主题(Subject)和观察者(Observer),并分别实现这两种模式。

推模式实现

在推模式中,主题在状态变化时主动将数据推送给观察者。

cpp 复制代码
class Observer:
   def update(self, message):
       raise NotImplementedError("You should implement this method.")


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, message):
       for observer in self._observers:
           observer.update(message)


class ConcreteSubject(Subject):
   def __init__(self):
       super().__init__()
       self._state = None

   def change_state(self, new_state):
       self._state = new_state
       print(f"Subject state changed to: {self._state}")
       self.notify(self._state)  # 推模式:将状态推送给观察者


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

   def update(self, message):
       print(f"Observer {self._name} received message: {message}")


if __name__ == "__main__":
   subject = ConcreteSubject()

   observer1 = ConcreteObserver("Observer 1")
   observer2 = ConcreteObserver("Observer 2")

   subject.attach(observer1)
   subject.attach(observer2)

   subject.change_state("State 1")
   subject.change_state("State 2")

拉模式实现

在拉模式中,观察者在需要数据时主动请求主题提供数据。

cpp 复制代码
class Observer:
   def update(self, subject):
       raise NotImplementedError("You should implement this method.")


class Subject:
   def __init__(self):
       self._observers = []
       self._state = None

   def attach(self, observer):
       self._observers.append(observer)

   def detach(self, observer):
       self._observers.remove(observer)

   def set_state(self, new_state):
       self._state = new_state
       print(f"Subject state changed to: {self._state}")
       self.notify()  # 通知观察者

   def notify(self):
       for observer in self._observers:
           observer.update(self)  # 拉模式:观察者请求状态


class ConcreteSubject(Subject):
   def get_state(self):
       return self._state


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

   def update(self, subject):
       state = subject.get_state()  # 拉模式:主动请求状态
       print(f"Observer {self._name} received state: {state}")


if __name__ == "__main__":
   subject = ConcreteSubject()

   observer1 = ConcreteObserver("Observer 1")
   observer2 = ConcreteObserver("Observer 2")

   subject.attach(observer1)
   subject.attach(observer2)

   subject.set_state("State 1")
   subject.set_state("State 2")

案例,登录异常的监测与提醒

cpp 复制代码
import time
from collections import defaultdict

# 抽象观察者
class Observer:
   def update(self, message):
       raise NotImplementedError("You should implement this method.")

# 抽象主题
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, message):
       for observer in self._observers:
           observer.update(message)

# 具体主题
class LoginMonitor(Subject):
   def __init__(self):
       super().__init__()
       self.login_attempts = defaultdict(list)  # 存储登录尝试
       self.threshold = 3  # 失败尝试阈值

   def record_login_attempt(self, username, ip_address, success):
       """记录登录尝试"""
       timestamp = time.time()
       self.login_attempts[username].append((timestamp, ip_address, success))
       self.check_for_anomalies(username)

   def check_for_anomalies(self, username):
       """检查异常登录行为"""
       attempts = self.login_attempts[username]
       failed_attempts = [attempt for attempt in attempts if not attempt[2]]
       
       # 检查连续失败的登录尝试
       if len(failed_attempts) >= self.threshold:
           last_failed_time = failed_attempts[-1][0]
           if time.time() - last_failed_time < 300:  # 5分钟内的失败尝试
               self.notify(f"Alert: Multiple failed login attempts detected for user '{username}'.")

# 具体观察者
class EmailAlert(Observer):
   def update(self, message):
       print(f"Email Alert: {message}")

class SMSAlert(Observer):
   def update(self, message):
       print(f"SMS Alert: {message}")

# 示例使用
if __name__ == "__main__":
   monitor = LoginMonitor()

   # 添加观察者
   email_alert = EmailAlert()
   sms_alert = SMSAlert()
   monitor.attach(email_alert)
   monitor.attach(sms_alert)

   # 模拟登录尝试
   monitor.record_login_attempt("user1", "192.168.1.1", False)
   monitor.record_login_attempt("user1", "192.168.1.1", False)
   monitor.record_login_attempt("user1", "192.168.1.1", False)  # 第三次失败,触发提醒
   monitor.record_login_attempt("user1", "192.168.1.1", True)   # 成功登录

在之前的代码示例中,login_attempts是一个 defaultdict,用于存储每个用户的登录尝试记录。具体来说,它的结构是一个字典,其中键是用户名,值是一个列表,列表中包含该用户的每次登录尝试的详细信息。

详细解释:

类型:defaultdict(list) 是 Python 的一个字典子类,允许在访问不存在的键时自动创建一个空列表。这样可以方便地向列表中添加元素,而不需要先检查键是否存在。

用途:login_attempts 用于记录每个用户的登录尝试,包括时间戳、IP 地址和登录结果(成功或失败)。例如,记录的每个登录尝试可以是一个元组,包含 (timestamp, ip_address, success)。

相关推荐
我的xiaodoujiao5 分钟前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
人邮异步社区19 分钟前
怎么把C语言学到精通?
c语言·开发语言
qetfw24 分钟前
MXU:Tauri 2 + React 的 MaaFramework 跨平台 GUI 源码
前端·python·react.js·前端框架·开源项目·效率工具
心平气和量大福大1 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai1 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
用户8356290780511 小时前
Python 实现 Excel 页面布局与打印设置自动化
后端·python
এ慕ོ冬℘゜1 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa1 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio
一次旅行1 小时前
Python+大模型端到端自动化日报系统
开发语言·python·自动化
天天爱吃肉82182 小时前
【电源拆解:跟着问答逐一认识开关适配器PCB元器件】
大数据·人工智能·python·功能测试·嵌入式硬件·汽车