c++ - 观察者模式不起作用
问题描述
所以我遇到了这个问题,我一直在为我的 OOP 考试练习,并且我尝试构建一个观察者设计模式。不幸的是,似乎每次我初始化一个接口时,它都会以某种方式复制我的控制器,这意味着观察者列表的新副本。因此,我的界面没有被更新。
我的观察者:
#pragma once
#include <vector>
#include <algorithm>
class Observer
{
public:
virtual void update() = 0;
virtual ~Observer() {}
};
class Observable
{
private:
std::vector<Observer*> observers;
public:
virtual ~Observable() {}
void addObserver(Observer *obs)
{
observers.push_back(obs);
}
void removeObserver(Observer *obs)
{
observers.erase(std::remove(observers.begin(), observers.end(), obs));
}
void notify()
{
for (auto obs : observers)
{
obs->update();
}
}
};
这是需要更新的界面:
class Practice : public QWidget, public Observer
{
Q_OBJECT
public:
Practice(Controller& ctrl, Teacher& t, QWidget *parent = Q_NULLPTR);
--------------
Practice::Practice(Controller& ctrl, Teacher& t, QWidget *parent) : ctrl{ ctrl }, t{ t }, QWidget(parent)
{
ui.setupUi(this);
QObject::connect(ui.studentList, &QListWidget::itemSelectionChanged, this, [this]() {this->listItemChanged(); });
QObject::connect(ui.gradeButton, &QPushButton::clicked, this, &Practice::on_gradeButton_clicked);
this->populateStudentsList();
this->ctrl.addObserver(this);
}
我的主要:(我打开的窗户和“老师”一样多)
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Repository repo("Student.txt", "Teacher.txt");
Controller ctrl(repo);
std::vector<Teacher> temp = ctrl.getRepo().getTeachers();
for (int i = 0; i < temp.size(); ++i)
{
Practice* p = new Practice{ctrl, temp[i]};
p->setWindowTitle(QString::fromStdString(temp[i].getName()));
p->show();
}
return a.exec();
}
另外,我的控制器继承自 Observable。
我对其进行了调试,得出的结论是,每次初始化“练习”时都会创建一个新控制器,但我不知道为什么。
谢谢你。
解决方案
我对其进行了调试,得出的结论是,每次初始化“练习”时都会创建一个新控制器,但我不知道为什么。
您没有显示您的类的完整声明Practice
,但从您的构造函数定义中可以清楚地看出该类中存在一个ctrl
成员。
如果该ctrl
成员未声明为引用 ( Controller&
),则当构造函数ctrl{ ctrl }
在成员初始化列表中调用时,即使输入对象通过引用传递给构造函数,也会生成输入对象的副本。ctrl
ctrl
如果该Controller
对象的寿命超过Practice
对象(似乎是这种情况),则考虑使该Practice::ctrl
成员成为输入Controller
对象的引用/指针,而不是它的副本:
class Practice : public QWidget, public Observer
{
...
private:
Controller &ctrl;
...
public:
Practice(Controller& ctrl, ...);
~Practice();
...
};
Practice::Practice(Controller& ctrl, ...) : ctrl{ ctrl }, ...
{
...
this->ctrl.addObserver(this);
}
Practice::~Practice()
{
...
this->ctrl.removeObserver(this);
}
或者:
class Practice : public QWidget, public Observer
{
...
private:
Controller *ctrl;
...
public:
Practice(Controller& ctrl, ...);
~Practice();
...
};
Practice::Practice(Controller& ctrl, ...) : ctrl{ &ctrl }, ...
{
...
this->ctrl->addObserver(this);
}
Practice::~Practice()
{
...
this->ctrl->removeObserver(this);
}
Controller
或者,考虑将对象包装在astd::shared_ptr<Controller>
中,然后将Practice::ctrl
成员声明为std::shared_ptr<Controller>
匹配。
class Practice : public QWidget, public Observer
{
...
private:
std::shared_ptr<Controller> ctrl;
...
public:
Practice(std::shared_ptr<Controller> ctrl, ...);
...
};
Practice::Practice(std::shared_ptr<Controller> ctrl, ...) : ctrl{ ctrl }, ...
{
...
this->ctrl->addObserver(this);
}
Practice::~Practice()
{
...
this->ctrl->removeObserver(this);
}
int main()
{
std::shared_ptr<Controller> ctrl = std::make_shared<Controller>(repo);
...
Practice* p = new Practice{ctrl, temp[i]};
...
}
无论哪种方式,多个Practice
对象都将能够共享一个Controller
对象。
推荐阅读
- python - 如何绘制多元线性回归的输出?
- git - Git忽略目录中的所有内容,但一种文件类型
- r - 如何找到两个单词模式只知道r中的第一个
- excel - 根据最新日期删除重复行
- python - 除以零时获得无穷大
- java - 用 Java 开发一个可重用的模板项目
- javascript - 当转换为 json2csv 时,所有标题和数据都来自相同的列。我们如何分离这些列?
- angular - 通过订阅主题()更新值后如何以角度重新渲染组件
- pentaho - 为什么 Kitchen 无法识别我的存储库?
- google-app-engine - 尝试将值附加到 wtforms 验证器时,为什么我在谷歌应用程序引擎上遇到烧瓶超时异常?