C++ Observer设计模式的学习

本周学习了几种设计模式,包括Template, Strategy, Observer, Decorator和Bridge,觉得都有用。本文重点回顾一下Observer设计模式。

Observer设计模式主要应用在当目标对象的状态发生改变的时候,所有的依赖对象(也就是观察者对象)都将得到通知并自动更新。说到"通知",有嵌入式背景的同学可能马上就会想到用polling和interrupt这两种方法,但我们这里说的设计模式是在应用层,跟底层的OS和hardware无关,其实完全是两个不同领域的东西。

这里要注意的是,目标对象发送通知时,无需指定观察者,通知会自动传播给已经订阅通知的观察者。目标对象并不知道谁是观察者。我们想象这样一个例子,假设有几百万个客户都订阅了一个微信公众号,这个公众号每天都发送一些八卦新闻。客户可以自己选择订阅或退订,公众号的任务就是发送新闻而已,所有的客户在它看来都一样,没有区别。它一发送新闻,那些客户就收到新闻了。这个例子就是一个观察者模式的实际运用。

观察者模式的结构描述如下图:
这里写图片描述

这里Subject和Observer之间是松耦合。Subject的Notify()里面会调用一个loop,遍历所有的观察者并调用它们的update()函数。在Subject看来所有的观察者都是一样的,它们的update()没有区别。Observer通过订阅/退订,可以决定要不要收到通知。

Observer设计模式在基于时间的UI框架中用的很多。一个具体例子如下:

class IProgress{
public:
	virtual void DoProgress(float value)=0;
	virtual ~IProgress(){}
};


class FileSplitter
{
	string m_filePath;
	int m_fileNumber;
    List<IProgress*>  m_iprogressList; // 抽象通知机制,支持多个观察者
	
public:
	FileSplitter(const string& filePath, int fileNumber) :
		m_filePath(filePath), 
		m_fileNumber(fileNumber){

	}
	void split(){

		//1.读取大文件
		//2.分批次向小文件中写入
		for (int i = 0; i < m_fileNumber; i++){
			//...
			float progressValue = m_fileNumber;
			progressValue = (i + 1) / progressValue;
			onProgress(progressValue);//发送通知
		}
	}

	void addIProgress(IProgress* iprogress){
		m_iprogressList.push_back(iprogress);
	}

	void removeIProgress(IProgress* iprogress){
		m_iprogressList.remove(iprogress);
	}

protected:
	virtual void onProgress(float value){
		
		List<IProgress*>::iterator itor=m_iprogressList.begin();

		while (itor != m_iprogressList.end() )
			(*itor)->DoProgress(value); //更新进度条
			itor++;
		}
	}
};

class MainForm : public Form, public IProgress
{
	TextBox* txtFilePath;
	TextBox* txtFileNumber;

	ProgressBar* progressBar;

public:
	void Button1_Click(){

		string filePath = txtFilePath->getText();
		int number = atoi(txtFileNumber->getText().c_str());

		ConsoleNotifier cn;

		FileSplitter splitter(filePath, number);

		splitter.addIProgress(this); //订阅通知
		splitter.addIProgress(&cn); //订阅通知

		splitter.split();

		splitter.removeIProgress(this);

	}

	virtual void DoProgress(float value){
		progressBar->setValue(value);
	}
};

class ConsoleNotifier : public IProgress {
public:
	virtual void DoProgress(float value){
		cout << ".";
	}
};

在这个例子中,FileSplitter是ConcreteSubject, MainForm和ConsoleNotifier都是客户(ConcreteObserver)。FileSplitter切割文件的时候,会调用onProgress()函数。onProgress()就相当于上面图里面的Notify(),里面会遍历m_iprogressList,这个就是客户列表。客户通过splitter.addIProgress()来订阅通知。

另外要注意的是,如果订阅的客户多了,Subject里面的Notify()就会比较慢,变成系统的瓶颈。看来这个Observer模式也是有局限性的。

下面是一个完整的observer模式的例子。代码参考自
https://blog.csdn.net/wuzhekai1985/article/details/6674984

#include <string>
#include <iostream>
using namespace std;
#include <list>

//pure virtual class, like JAVA's interface
class Observer  
{
public:
	Observer() {}
	virtual ~Observer() {}
	virtual void Update() {} 
};

class Blog  
{
public:
	Blog() {}
	virtual ~Blog() {}
	void Attach(Observer *observer) { m_observers.push_back(observer); }
	void Remove(Observer *observer) { m_observers.remove(observer); }
	void Notify()
	{
		list<Observer*>::iterator iter = m_observers.begin();
		for(; iter != m_observers.end(); iter++)
			(*iter)->Update();
	}
	virtual void SetStatus(string s) { m_status = s; }
	virtual string GetStatus() { return m_status; }
private:
	list<Observer* > m_observers;
protected:
	string m_status;
};


class BlogCSDN : public Blog
{
private:
	string m_name;
public:
	BlogCSDN(string name): m_name(name) {}
	~BlogCSDN() {}
	void SetStatus(string s) { m_status = "CSDN Notice : " + m_name + s; }
	string GetStatus() { return m_status; }
};

class ObserverBlog : public Observer   
{
private:
	string m_name;
	Blog *m_blog;
public: 
	ObserverBlog(string name,Blog *blog): m_name(name), m_blog(blog) {}
	~ObserverBlog() {}
	void Update()
	{ 
		string status = m_blog->GetStatus();
		cout<<m_name<<"-------"<<status<<endl;
	}
};

int main()
{
	Blog *blog = new BlogCSDN("roufoo");
	Observer *observer1 = new ObserverBlog("Tom", blog);
	Observer *observer2 = new ObserverBlog("Jerry", blog);
	blog->Attach(observer1);
	blog->Attach(observer2);
	blog->SetStatus("roufoo's new post published"");
	blog->Notify();
	delete blog; 
	delete observer1;
	delete observer2;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下是一个使用观察者(Observer设计模式的示例代码(C++): ```cpp #include <iostream> #include <vector> // 观察者接口 class Observer { public: virtual void update(const std::string& message) = 0; }; // 具体观察者A class ConcreteObserverA : public Observer { public: void update(const std::string& message) override { std::cout << "具体观察者A收到消息:" << message << std::endl; } }; // 具体观察者B class ConcreteObserverB : public Observer { public: void update(const std::string& message) override { std::cout << "具体观察者B收到消息:" << message << std::endl; } }; // 被观察者(主题)类 class Subject { private: std::vector<Observer*> observers; std::string message; public: void attach(Observer* observer) { observers.push_back(observer); } void detach(Observer* observer) { for (auto it = observers.begin(); it != observers.end(); ++it) { if (*it == observer) { observers.erase(it); break; } } } void notify() { for (auto observer : observers) { observer->update(message); } } void setMessage(const std::string& newMessage) { message = newMessage; notify(); } }; // 客户端代码 int main() { // 创建具体观察者对象 Observer* observerA = new ConcreteObserverA(); Observer* observerB = new ConcreteObserverB(); // 创建被观察者对象 Subject subject; // 注册观察者 subject.attach(observerA); subject.attach(observerB); // 设置消息并通知观察者 subject.setMessage("Hello World!"); // 取消注册观察者B subject.detach(observerB); // 设置新消息并通知观察者 subject.setMessage("Goodbye!"); delete observerA; delete observerB; return 0; } ``` 在上述示例代码中,我们定义了一个观察者接口 `Observer`,并要求具体的观察者类继承并实现该接口。具体的观察者类 `ConcreteObserverA` 和 `ConcreteObserverB` 分别定义了不同的更新行为。 被观察者(主题)类 `Subject` 包含一个观察者列表,并提供了注册、注销和通知观察者的方法。通过调用 `notify()` 方法,被观察者会遍历观察者列表,并调用每个观察者的 `update()` 方法来传递消息。 在客户端代码中,我们创建了具体的观察者对象,并将它们注册到被观察者中。然后,通过设置消息并调用被观察者的 `setMessage()` 方法来通知观察者。在示例中,我们设置了两条消息,并在第二条消息后注销了一个观察者。 运行代码将输出每个观察者收到的消息。 这个示例展示了观察者设计模式的基本结构和使用方式,并在 C++ 中实现了它。通过使用观察者模式,可以实现对象之间的松耦合,当一个对象的状态发生变化时,它的所有观察者都会得到通知并进行相应的处理。记得在程序结束时删除动态分配的内存。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值