黄国强 2023/06/09
为了将 Data 和 Ouput 解耦,我们这里的 Data 和 Ouput 是使用观察者模式来交互。Data 是主题,Ouput 是观察者。代码如下。
// 观察者
class Output
{
// Regist 主题时,主题回调此函数,参数是 json 格式的主题信息
void SubjectInfo(const Json::Value& val);
// 观察者模式的主题调用此函数输出内容
void SubjectUpdate(const std::string& val);
void SubjectUpdate(int val);
void SubjectUpdate(double val);
void SubjectUpdate(const Json::Value& val);
};
// 主题
class Data
{
public:
// 向观察者发布主题
void Publish();
// 注册指定 Output 观察者
void Regist(Output * p);
// 注销指定 Output 观察者
void RegistUn(Output * p);
};
我们准备在 QT 的对话框中显示 “Hello World”。所以,这个字符串观察类应该从 Output 继承。同时我们再创建一个字符串主题类。下面是类图,图中 AfcQtEdit 是观察类,DataString 是字符串主题类。
AfcQtEdit 代码如下。
///
class AfcQtEdit : public Output
{
public:
AfcQtEdit(QLabel * pLable, QLineEdit * pEdit);
protected: // Output
virtual void DoSubjectUpdate(const std::string& val);
private:
QLabel * _pLable{ nullptr };
QLineEdit * _pEdit{ nullptr };
};
/// AfcQtEdit
AfcQtEdit::AfcQtEdit(QLabel * pLable, QLineEdit * pEdit)
: _pLable(pLable)
, _pEdit(pEdit)
{
}
void AfcQtEdit::DoSubjectUpdate(const std::string & val)
{
_pEdit->setText(QString::fromLocal8Bit(val.c_str()));
}
在QT 的对话框中添加如下代码。
/// QT 对话框
class TestAFC : public QDialog
{
Q_OBJECT
public:
TestAFC(QWidget *parent = nullptr);
~TestAFC();
private:
Ui::TestAFCClass *ui;
std::shared_ptr<AfcQtEdit> _pEdit;
AFC::DataPtr _pData;
};
/// TestAFC
TestAFC::TestAFC(QWidget *parent)
: QDialog(parent)
, ui(new Ui::TestAFCClass())
{
ui->setupUi(this);
_pEdit.reset(new AfcQtEdit(ui->label, ui->lineEdit)); // 创建一个字符串观察者
_pData = Data::CreateObj("string"); // 创建 String 主题,默认值是 "Hello World!"
_pData->Regist(_pEdit.get()); // 注册一个观察者
_pData->Publish(); // 将主题发布给所有观察者
}
TestAFC::~TestAFC()
{
delete ui;
}
最终效果如下图。
正如上面提到的,这样的设计达到了解耦的目的。后续主题和显示是独立发展的。比如,Output 可以增加对 MFC, WPF 甚至浏览器的支持,而 Data 无需进行任何修改。
[参考链接]