观察者模式定义了一对多的依赖关系,当一个对象改变时,它的所有依赖者都会收到通知并自动更新。类似很多人订阅了一个公众号,一旦公众号发送消息,订阅的人都会收到消息。
经典的观察者模式在讲解举例的时候通常会举报纸和订阅者的例子。有一个报纸Newspaper,有一个订阅者类Subscriber。Subscriber可以订阅Newspaper。这样,当Newspaper有了新的内容的时候,Subscriber可以立即得到通知。在这个例子中,观察者是Subscriber,被观察者是Newspaper。在经典的实现代码中,观察者会将自身注册到被观察者的一个容器中。被观察者发生了任何变化的时候,会主动遍历这个容器,依次通知各个观察者。
例如:以不同的显示形式显示某一数据,LCD显示、Label中显示等
1)定义一个被观察对象(目标),其中可以有任意多个观察者,需要提供添加和删除观察者的接口,在被观察对象中定义通知观察者接口
2)定义观察者父类,添加刷新的虚函数接口
3)定义不同的观察者子类,重写刷新接口
实现代码如下:
观察者父类
class Observer : public QWidget
{
public:
Observer();
//触发更新的接口
virtual void update(const int ) const = 0;
};
Label显示数据的子类观察者
.h代码
class ObserverLabel : public Observer
{
public:
ObserverLabel();
//触发更新
void update(const int value) const override;
private:
QLabel *m_label;
};
.cpp代码
ObserverLabel::ObserverLabel()
{
m_label = new QLabel("Text");
QHBoxLayout *layout = new QHBoxLayout();
layout->addWidget(m_label);
this->setLayout(layout);
}
void ObserverLabel::update(const int value) const
{
m_label->setText(QString::number(value));
}
LCD显示的子类观察者
.h代码
class ObserverLcd : public Observer
{
public:
ObserverLcd();
//触发更新
void update(const int value) const override;
private:
QLCDNumber *m_lcdNum;
};
.cpp代码
ObserverLcd::ObserverLcd()
{
m_lcdNum = new QLCDNumber();
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(m_lcdNum);
this->setLayout(layout);
}
void ObserverLcd::update(const int value) const
{
m_lcdNum->display(value);
}
被观察对象实现
.h代码
class Subject
{
public:
Subject();
//添加观察者
void addObserver(Observer *obs);
//移除观察者
void removeObserver(Observer *obs);
//触发观察者更新
void setValue(const int value);
private:
QList<Observer*> m_observers;
};
.cpp代码
void Subject::addObserver(Observer *obs)
{
m_observers.append(obs);
}
void Subject::removeObserver(Observer *obs)
{
m_observers.removeOne(obs);
}
void Subject::setValue(const int value)
{
for(int i=0; i<m_observers.length(); i++)
{
m_observers.at(i)->update(value);
}
}
调用实现代码
.h代码
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
//添加label观察者
void on_btnAddLabel_clicked();
//添加lcd观察者
void on_btnAddLcd_clicked();
//触发观察者更新
void on_spinBox_valueChanged(int arg1);
private:
Ui::MainWindow *ui;
Subject m_subject;
};
.cpp代码
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_spinBox_valueChanged(int arg1)
{
m_subject.setValue(arg1);
}
void MainWindow::on_btnAddLabel_clicked()
{
ObserverLabel *histogram = new ObserverLabel;
m_subject.addObserver(histogram);
ui->hLayout->addWidget(histogram);
}
void MainWindow::on_btnAddLcd_clicked()
{
ObserverLcd *lcd = new ObserverLcd;
m_subject.addObserver(lcd);
ui->hLayout->addWidget(lcd);
}