【问题标题】:Observer Pattern not working观察者模式不起作用
【发布时间】:2018-06-14 19:22:18
【问题描述】:

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

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

谢谢。

【问题讨论】:

标签: c++ observer-pattern


【解决方案1】:

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

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

如果该ctrl 成员未声明为引用(Controller&amp;),则当构造函数在成员初始化列表中调用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 对象包装在std::shared_ptr&lt;Controller&gt; 中,然后将Practice::ctrl 成员声明为std::shared_ptr&lt;Controller&gt; 以进行匹配。

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 对象。

【讨论】:

    【解决方案2】:

    谢谢,但显然我忘了在类的定义中引用控制器……我的错。谢谢大家,祝你有美好的一天!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-02-20
      • 2023-04-10
      • 1970-01-01
      • 1970-01-01
      • 2016-05-11
      • 1970-01-01
      • 2022-12-14
      • 1970-01-01
      相关资源
      最近更新 更多