编程 c++ 设计模式-观察者模式(Observer Pattern)

2024-11-18 19:11:17 +0800 CST views 679

设计模式-观察者模式(Observer Pattern)

概述

**观察者模式(Observer Pattern)**是一种行为型设计模式,它定义了对象之间的一对多依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。这种模式通常用于实现分布式事件处理系统。

1. 观察者模式的定义

观察者模式允许对象间进行广播通信,即一个对象状态发生改变时,多个依赖该对象的观察者对象将被通知。此模式可以解耦发布者和订阅者,允许它们独立变化。

C++中的观察者模式实现示例

以下是一个使用C++实现的观察者模式示例,展示了如何实现观察者(Observer)和被观察者(Subject)之间的依赖关系。

#include <iostream>
#include <list>
#include <algorithm>

// 观察者基类
class Observer {
public:
    virtual ~Observer() {}
    virtual void update(int state) = 0;
};

// 被观察者基类
class Subject {
public:
    virtual ~Subject() {}
    virtual void attach(Observer* observer) {
        observers.push_back(observer);
    }
    virtual void detach(Observer* observer) {
        observers.remove(observer);
    }
    virtual void notify() {
        for (auto* observer : observers) {
            observer->update(state);
        }
    }
protected:
    std::list<Observer*> observers;
    int state;
};

// 具体观察者
class ConcreteObserver : public Observer {
public:
    void update(int state) override {
        std::cout << "Observer: Subject's state changed to " << state << std::endl;
    }
};

// 具体被观察者
class ConcreteSubject : public Subject {
public:
    void setState(int newState) {
        state = newState;
        notify();
    }
};

int main() {
    ConcreteSubject subject;
    ConcreteObserver observerA;
    ConcreteObserver observerB;

    subject.attach(&observerA);
    subject.attach(&observerB);

    subject.setState(1); // 通知所有观察者

    subject.detach(&observerA);

    subject.setState(2); // 通知所有观察者

    return 0;
}

代码说明

  1. Subject 类:被观察者基类,维护了观察者列表并提供 attachdetach 方法来管理观察者。
  2. Observer 类:观察者基类,定义了 update 方法用于在状态变化时更新。
  3. ConcreteObserver 类:具体观察者类,响应被观察者的状态变化。
  4. ConcreteSubject 类:具体被观察者类,通过 setState 方法修改状态并通知观察者。

main 函数中,我们创建了 ConcreteSubject 对象和两个 ConcreteObserver 对象,展示了观察者模式的使用流程。

2. 观察者模式的优缺点

2.1 优点

  • 解耦:被观察者和观察者解耦,使得两者的依赖关系降低。
  • 扩展性:可以轻松地增加新的观察者,而不需要修改现有的被观察者代码。
  • 灵活性:观察者可以根据被观察者状态的变化作出不同响应。
  • 广播通信:支持同时通知多个观察者对象。
  • 松散关联:被观察者和观察者之间的关系松散,使得系统更灵活。

2.2 缺点

  • 性能开销:在观察者较多的情况下,频繁的状态通知会带来性能开销。
  • 循环依赖:如果不小心,可能会产生循环依赖问题。
  • 通知顺序不定:多个观察者接收通知的顺序通常是随机的。

3. 观察者模式的应用场景

  • 事件处理系统:在GUI编程中处理用户的行为(如点击、滚动)。
  • 游戏开发:监听游戏状态的变化,更新UI或触发动作。
  • MVC架构:用于视图和控制器对模型数据变化的依赖关系。
  • 发布-订阅系统:跨组件通信的理想方案。
  • 股票监控系统:监听股票价格变化并通知投资者或自动执行交易。

4. 如何确保线程安全

在多线程环境下实现观察者模式时,确保线程安全非常重要。以下策略可用于确保线程安全:

  • 使用同步方法:通过互斥锁 std::mutex 来确保方法的线程安全。
  • 使用读写锁:通过 std::shared_mutex 来区分读写锁,从而提高性能。
  • 线程安全容器:如 ConcurrentHashMapstd::vector,减少手动同步的复杂性。
  • 避免在通知过程中修改观察者列表:在通知之前创建观察者列表的副本。
  • 使用条件变量:协调观察者和被观察者的更新操作。
  • 使用不可变对象:确保传递的状态是不可变的,从而避免并发问题。
  • 使用原子操作:在简单状态更新时使用原子操作来保证安全性。

5. 避免观察者模式中的死锁问题

在多线程环境中使用观察者模式时,避免死锁的关键措施包括:

  • 锁顺序:确保获取锁的顺序一致,避免循环等待。
  • 锁超时:为锁操作设置超时,避免长期等待。
  • 最小化锁持有时间:减少锁定的代码块。
  • 避免嵌套锁:避免同时持有多个锁,以减少死锁可能性。

结论

观察者模式在解耦和扩展性方面具有显著优势,但在多线程环境中需要额外的同步措施来确保线程安全。通过合理设计,可以在提高系统灵活性的同时,保持高效的性能。

复制全文 生成海报 设计模式 编程 多线程

推荐文章

PHP 微信红包算法
2024-11-17 22:45:34 +0800 CST
windows安装sphinx3.0.3(中文检索)
2024-11-17 05:23:31 +0800 CST
介绍25个常用的正则表达式
2024-11-18 12:43:00 +0800 CST
php常用的正则表达式
2024-11-19 03:48:35 +0800 CST
MySQL设置和开启慢查询
2024-11-19 03:09:43 +0800 CST
java MySQL如何获取唯一订单编号?
2024-11-18 18:51:44 +0800 CST
Vue 3 路由守卫详解与实战
2024-11-17 04:39:17 +0800 CST
一键压缩图片代码
2024-11-19 00:41:25 +0800 CST
企业官网案例-芊诺网络科技官网
2024-11-18 11:30:20 +0800 CST
Python上下文管理器:with语句
2024-11-19 06:25:31 +0800 CST
批量导入scv数据库
2024-11-17 05:07:51 +0800 CST
关于 `nohup` 和 `&` 的使用说明
2024-11-19 08:49:44 +0800 CST
Golang 几种使用 Channel 的错误姿势
2024-11-19 01:42:18 +0800 CST
JavaScript数组 splice
2024-11-18 20:46:19 +0800 CST
Vue3中如何处理权限控制?
2024-11-18 05:36:30 +0800 CST
使用Rust进行跨平台GUI开发
2024-11-18 20:51:20 +0800 CST
程序员茄子在线接单