观察者模式不起作用

时间:2018-06-14 19:22:18

标签: c++ observer-pattern

所以我遇到了这个问题,我一直在为我的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);
}

我的主要人物:(我打开的窗户数量与#34;教师和#34相同;)

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。

我对它进行了调试,我得出的结论是每次初始化&#34;练习&#34;时都会创建一个新的控制器。而且我不知道为什么。

谢谢。

2 个答案:

答案 0 :(得分:1)

  

我调试了它,我得出的结论是每次初始化“练习”时都会创建一个新的控制器而我不知道为什么。

您没有显示Practice类的完整声明,但从构造函数定义可以清楚地看出,该类中存在ctrl成员。< / p>

如果ctrl成员未被声明为引用(Controller&),那么当构造函数在成员初始化列表中调用ctrl{ ctrl }时,副本即使输入ctrl对象通过引用传递给构造函数,也会生成输入ctrl对象。

如果Controller对象的意图比Practice对象更长(似乎是这种情况),那么考虑使Practice::ctrl成员成为输入的引用/指针{ {1}}对象,而不是它的副本

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内,然后将std::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对象。

答案 1 :(得分:0)

谢谢,但显然我忘了在班级的定义中引用控制器...我的不好。谢谢大家,祝你有个美好的一天!