观察者(Observer)
观察者模式属于设计模式::行为模式的一种,特别的,属于行为对象模式。
行为模式涉及到算法和对象间职责的分配。行为模式不仅描述对象或类的模式,还描述他们之间的通信模式(协作)。
行为模式分为两种:
- 行为类模式:使用继承机制在类间分配行为。
- 行为对象模式:使用对象复合而不是继承。
一言以蔽之
一对多的依赖关系,一个改变,所有依赖他的对象(即观察者)都得到更新。
目的:通知(抽象的通知机制)
举例:更新进度条,需要将进度值传出;MVC架构:Model改变,所有的View都会得到通知。
举例1-进度条
伪代码:
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){
for(auto observer : m_iprogressList)
observer->DoProgress(value);
}
};
// MainForm为观察者
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); // 取消订阅
}
// 实现接口
void DoProgress(float value) override {
progressBar->setValue(value);
}
};
// 另一个观察者
class ConsoleNotifier : public IProgress {
public:
virtual void DoProgress(float value){
cout << ".";
}
};
举例2-MVC
- 模型(Model) 用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。Model 有对数据直接访问的权力,例如对数据库的访问。Model不依赖View和Controller,也就是说, Model 不关心它会被如何显示或是如何被操作。但是 Model 中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此 Model 的 View 必须事先在此 Model 上注册,从而,View 可以了解在数据 Model 上发生的改变。
- **视图(View)**能够实现数据有目的的显示(理论上而已,不是必需的)。在 View 中一般没有程序上的逻辑。为了实现 View 上的刷新功能,View 需要访问它监视的数据模型Model,因此应该事先在被它监视的数据那里注册。(View是Model的观察者)
- **控制器(Controller)**起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”(Event)包括用户的行为和数据 Model 上的改变(比如UI就是事件驱动的)。
注意:MVC是一种设计理念,不是必须的,但是使用了会让软件的架构看起来更好,解耦合。
Controller manipulates Model:控制器Controller操作数据
Model updates View:观察者View需要在Model中注册,Model就可以通知View啦
View saw by Users, Users use Controller:沟通View与Controller之间的桥梁就是User用户啦,用户看View,想修改时,使用控制器Controller来操控Model。
模板:
// 可以订阅、取消订阅
Attach(Observer* o){ // addObserver(IProcess* iptr);
Observers.append(o);
}
Detach(Observer* o){ // removeObserver();
Observers.remove(o);
}
// 通知
Notify(){
for(var o : Observers)
o->Update(); // Update()可以是观察者的方法
}
相关模式
- 中介者(Mediator)
- 单例模式(Singleton)