C++ 全栈知识体系C++ 全栈知识体系
✿导航
  • 基础
  • 函数
  • 知识点
  • IO框架
  • 新版本特性
  • 数据库原理
  • SQL语言
  • SQL - MySQL
  • NoSQL - Redis
  • NoSQL - ElasticSearch
  • 算法基础
  • 常见算法
  • 领域算法
  • 分布式算法
  • 数据结构与算法
  • 计算机网络
  • 操作系统
  • 计算机组成
  • 开发
  • 测试
  • 架构基础
  • 分布式系统
  • 微服务
  • 中间件
  • 概念
  • 理论
  • 架构设计原则
  • 设计模式
  • 协议
  • 技术选型
  • 编码规范
  • 流水线构建 - CI/CD
  • 知识点 - Linux
  • 网站 - Nginx
  • 容器化 - Docker
  • 容器编排 - Kubernetes
  • 服务网格 - Service Mesh Istio
  • 常用快捷键 - Shortcut
  • 工具使用 - Tools
  • 开源项目
  • 学习项目
  • 个人项目
  • 项目开发
  • 项目Idea
  • 并发
  • 部署
  • 分布式
  • 知识
  • 问题
  • 编程语言与技术
  • 系统与架构
  • 软件开发实践
  • 数据处理与应用设计
  • 个人
  • 产品
  • 团队
  • 知识体系
  • Vue
关于
✿导航
  • 基础
  • 函数
  • 知识点
  • IO框架
  • 新版本特性
  • 数据库原理
  • SQL语言
  • SQL - MySQL
  • NoSQL - Redis
  • NoSQL - ElasticSearch
  • 算法基础
  • 常见算法
  • 领域算法
  • 分布式算法
  • 数据结构与算法
  • 计算机网络
  • 操作系统
  • 计算机组成
  • 开发
  • 测试
  • 架构基础
  • 分布式系统
  • 微服务
  • 中间件
  • 概念
  • 理论
  • 架构设计原则
  • 设计模式
  • 协议
  • 技术选型
  • 编码规范
  • 流水线构建 - CI/CD
  • 知识点 - Linux
  • 网站 - Nginx
  • 容器化 - Docker
  • 容器编排 - Kubernetes
  • 服务网格 - Service Mesh Istio
  • 常用快捷键 - Shortcut
  • 工具使用 - Tools
  • 开源项目
  • 学习项目
  • 个人项目
  • 项目开发
  • 项目Idea
  • 并发
  • 部署
  • 分布式
  • 知识
  • 问题
  • 编程语言与技术
  • 系统与架构
  • 软件开发实践
  • 数据处理与应用设计
  • 个人
  • 产品
  • 团队
  • 知识体系
  • Vue
关于
  • 概念

    • 概念 - 概述
    • 概念 - 计算机专有名词
    • 概念 - 正向代理和反向代理
    • 概念 - 云网络
    • 概念 - rest api
    • 概念 - 脑裂
  • 理论

    • 事务理论 - ACID
    • 分布式理论 - CAP
    • 分布式理论 - BASE
  • 架构设计原则

    • 架构设计原则 - 合适、简单、演化
    • 架构设计原则 - 高内聚、低耦合
    • 架构设计原则 - 正交四原则
    • 架构设计原则 - SOLID详解
    • 架构设计原则 - 分层架构MVC
    • 架构设计原则 - DDD领域驱动设计:贫血模型和充血模型
    • 架构设计原则 - DDD领域驱动设计
  • 设计模式

    • 创建型模式 - Create model

      • 创建型模式 - 单例模式(Singleton)
      • 创建型模式 - 工厂模式(Factory)
      • 创建型模式 - 抽象工厂(Abstract Factory)
      • 创建型模式 - 生成器(Builder)
      • 创建型模式 - 原型模式(Prototype)
    • 结构型模式 - Structural model

      • 结构型模式 - 外观(Facade)
      • 结构型模式 - 适配器(Adapter)
      • 结构型模式 - 桥接(Bridge)
      • 结构型模式 - 组合(Composite)
      • 结构型模式 - 装饰(Decorator)
      • 结构型模式 - 享元(Flyweight)
      • 结构型模式 - 代理(Proxy)
    • 行为型模式 - Behavioral model

      • 行为型模式 - 责任链(Chain Of Responsibility)
      • 行为型模式 - 策略(Strategy)
      • 行为型模式 - 模板模式(Template)
      • 行为型模式 - 命令模式(Command)
      • 行为型模式 - 观察者(Observer)
      • 行为型模式 - 访问者(Visitor)
      • 行为型模式 - 状态(State)
      • 行为型模式 - 解释器(Interpreter)
      • 行为型模式 - 迭代器(Iterator)
      • 行为型模式 - 中介者(Mediator)
      • 行为型模式 - 备忘录(Memento)
  • 协议

    • 协议 - Http
    • 协议 - SNMP
    • 协议 - NETCONF
    • 协议 - TLS和SSL
    • 协议 - Http-wiki
    • 协议 - TCP/IP
    • 协议 - Https常见的认证模式
  • 技术选型

    • 技术选型 - 常用的技术框架
    • 技术选型 - 如何写一个自己的项目
    • 技术选型 - 基于drogon实现用户中心后端
  • 编码规范

    • 编码规范 - Google C++ Style Guide
    • 编码规范 - 编程风格
    • 编码规范 - 头文件包含规范
    • 编码规范 - 常用编码命名规则
    • 编码规范 - 编码命名规范

行为型 - 观察者(Observer)

观察者模式(Observer): 定义了一种一对多的依赖关系,让多个观察者对象同时监听某一主题对象,在它的状态发生变化时,会通知所有的观察者。

​[[toc]]

抛砖引玉

Observer 模式应该可以说是应用最多、影响最广的模式之一,因为 Observer 的一个实例 Model/View/Control( MVC) 结构在系统开发架构设计中有着很重要的地位和意义, MVC实现了业务逻辑和表示层的解耦。

Observer 模式要解决的问题为:建立一个一(Subject)对多( Observer) 的依赖关系, 并且做到当“一”变化的时候, 依赖这个“一”的多也能够同步改变。

最常见的一个例子就是:对同一组数据进行统计分析时候,希望能够提供多种形式的表示(例如以表格进行统计显示、 柱状图统计显示、 百分比统计显示等)。这些表示都依赖于同一组数据,当然需要当数据改变的时候,所有的统计的显示都能够同时改变。Observer 模式就是解决了这一个问题。

Observer 模式典型的结构图为:

具体思路解析:

  1. Subject 提供依赖于它的观察者 Observer 的注册(Attach)和注销(Detach)操作,并且提供了使得依赖于它的所有观察者同步的操作(Notify)。

  2. Subject通过维护list<Observer* >* _obvs,Object维护Subject* _sub,使用时。先创建Subject* sub,然后将其作为变量传递给Observer* o1,o2,使得ConcreteObserver在构造时完成Attach操作,将监听对象加入Subject的监听队列_obvs。

  3. Subject* sub 通过SetState函数改变状态,在调用Notify去遍历监听队列_obvs,更新Observer* o1,o2的状态。

代码实现

#ifndef _SUBJECT_H_
#define _SUBJECT_H_
#include <list>
#include <string>

using namespace std;
typedef string State;

class Observer;

class Subject
{
public:
	virtual ~Subject();
	virtual void Attach(Observer *obv);
	virtual void Detach(Observer *obv);
	virtual void Notify();
	virtual void SetState(const State &st) = 0;
	virtual State GetState() = 0;

protected:
	Subject();

private:
	list<Observer *> *_obvs;
};

class ConcreteSubject : public Subject
{
public:
	ConcreteSubject();
	~ConcreteSubject();
	State GetState();
	void SetState(const State &st);

protected:
private:
	State _st;
};
#endif //~_SUBJECT_H_

#include "Subject.h"
#include "Observer.h"
#include <iostream>
#include <list>
using namespace std;
typedef string state;

Subject::Subject()
{ //在模板的使用之前一定要 new,创建
	_obvs = new list<Observer *>;
}

Subject::~Subject()
{
}

void Subject::Attach(Observer *obv)
{
	_obvs->push_front(obv);
}

void Subject::Detach(Observer *obv)
{
	if (obv != NULL)
	{
		_obvs->remove(obv);
	}
}

void Subject::Notify()
{
	list<Observer *>::iterator it;
	it = _obvs->begin();
	for (; it != _obvs->end(); it++)
	{ //关于模板和 iterator 的用法
		(*it)->Update(this);
	}
}

ConcreteSubject::ConcreteSubject() //会隐式调用基类的默认构造函数
{
	_st = '\0';
}

ConcreteSubject::~ConcreteSubject()
{
}

State ConcreteSubject::GetState()
{
	return _st;
}

void ConcreteSubject::SetState(const State &st)
{
	_st = st;
}

#ifndef _OBSERVER_H_
#define _OBSERVER_H_

#include "Subject.h"
#include <string>

using namespace std;
typedef string State;

class Observer
{
public:
	virtual ~Observer();
	virtual void Update(Subject *sub) = 0;
	virtual void PrintInfo() = 0;

protected:
	Observer();
	State _st;

private:
};

class ConcreteObserverA : public Observer
{
public:
	virtual Subject *GetSubject();
	ConcreteObserverA(Subject *sub);
	virtual ~ConcreteObserverA();
	//传入 Subject 作为参数,这样可以让一个View 属于多个的 Subject。
	void Update(Subject *sub);
	void PrintInfo();

protected:
private:
	Subject *_sub;
};

class ConcreteObserverB : public Observer
{
public:
	virtual Subject *GetSubject();
	ConcreteObserverB(Subject *sub);
	virtual ~ConcreteObserverB();
	//传入 Subject 作为参数,这样可以让一个View 属于多个的 Subject。
	void Update(Subject *sub);
	void PrintInfo();

protected:
private:
	Subject *_sub;
};
#endif //~_OBSERVER_H_

#include "Observer.h"
#include "Subject.h"
#include <iostream>
#include <string>

using namespace std;

Observer::Observer()
{
	_st = '\0';
}

Observer::~Observer()
{
}

ConcreteObserverA::ConcreteObserverA(Subject *sub)
{
	_sub = sub;
	_sub->Attach(this);
}

ConcreteObserverA::~ConcreteObserverA()
{
	_sub->Detach(this);
	if (_sub != 0)
		delete _sub;
}

Subject *ConcreteObserverA::GetSubject()
{
	return _sub;
}

void ConcreteObserverA::PrintInfo()
{
	cout << "ConcreteObserverA observer...." << _sub->GetState() << endl;
}

void ConcreteObserverA::Update(Subject *sub)
{
	_st = sub->GetState();
	PrintInfo();
}

ConcreteObserverB::ConcreteObserverB(Subject *sub)
{
	_sub = sub;
	_sub->Attach(this);
}

ConcreteObserverB::~ConcreteObserverB()
{
	_sub->Detach(this);
	if (_sub != 0)
	{
		delete _sub;
	}
}

Subject *ConcreteObserverB::GetSubject()
{
	return _sub;
}

void ConcreteObserverB::PrintInfo()
{
	cout << "ConcreteObserverB observer...." << _sub->GetState() << endl;
}

void ConcreteObserverB::Update(Subject *sub)
{
	_st = sub->GetState();
	PrintInfo();
}

#include "Subject.h"
#include "Observer.h"
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
	Subject *sub = new ConcreteSubject();
	Observer *o1 = new ConcreteObserverA(sub);
	Observer *o2 = new ConcreteObserverB(sub);

	sub->SetState("old");
	sub->Notify();
	sub->SetState("new"); // 也可以由Observer 调用
	sub->Notify();

	return 0;
}

执行结果如下,因为list是头插法,后加入的ConcreteObserverB在sub广播通知list的开头,所以通知的消息先到达B:

[root@192 base_use]# ./ObserverTest
ConcreteObserverB observer....old
ConcreteObserverA observer....old
ConcreteObserverB observer....new
ConcreteObserverA observer....new

代码说明

在 Observer 模式的实现中:

  1. Subject 维护一个 list 作为存储其所有观察者的容器。每当调用 Notify 操作就遍历 list 中的 Observer 对象, 并广播通知改变状态(调用 Observer 的 Update操作)。

  2. 目标的状态 state 可以由 Subject 自己改变(示例),也可以由 Observer 的某个操作引起 state 的改变(可调用 Subject 的 SetState 操作。

  3. Notify 操作可以由 Subject 目标主动广播(示例),也可以由 Observer 观察者来调用(因为 Observer 维护一个指向 Subject 的指针)。

  4. 运行示例程序,可以看到当 Subject 处于状态“old” 时候, 依赖于它的两个观察者都显示“old”,当目标状态改变为“ new”的时候,依赖于它的两个观察者也都改变为“ new”。

讨论

Observer 是影响极为深远的模式之一,也是在大型系统开发过程中要用到的模式之一。除了 MFC、 Struts 提供了 MVC 的实现框架, 在 Java 语言中还提供了专门的接口实现 Observer模式:通过专门的类 Observable 及 Observer 接口来实现 MVC 编程模式, 其 UML 图可以表示为

这里的 Observer 就是观察者, Observable 则充当目标 Subject 的角色。Observer 模式也称为发布-订阅(publish-subscribe),目标就是通知的发布者,观察者则是通知的订阅者(接受通知)。 ​

Last Updated:
Contributors: klc407073648
Prev
行为型模式 - 命令模式(Command)
Next
行为型模式 - 访问者(Visitor)