3.文档视图:从gui分割状态

  为了解决一个类实现所有功能的缺陷,我们把application分为2个部分。一个部分业务逻辑,一个部分视觉渲染和交互。这2个类在学术上被称为document view 或者 model

delegate。

   Document类用来处理业务逻辑,和视觉渲染、GUI事件没有一点关系。它简单的存储应用程序的状态,提供接口获得状态并根据应用程序规则改变状态。另外,提供机制告知相关对象,应用程序状态改变。

  View类处理事件和图像渲染。提供对 Document类的操作,界面改变和 Document类中状态改变同步。

   Document View设计模式实现状态和图像显示分离,它们能单独的改变。Document类成为 non-GUI单元,能单独的工作和检测。任何View通过notification system保持和Document内容一致,并根据Document内容 负责图像呈现和用户交互。

  这种设计消除了一些对单个类实现的担忧,对状态和业务逻辑的测试变得更容易:通过调用Document类中的方法。此Document对象现在是独立的,如果需要的话,可以和不同的View工作。代价就是告知View,Document中状态改变(notification system)。

 

代码如下:

 model.h

#include <QSet>
#include <view.h>

class View;

class Model
{
public:
    Model();
    int getClickTimes() const;
    void setClickTimes(int value);
    void incrementClickTimes();
    void addListener(View *v);
    void removeListener(View *v);

private:
    int m_clickTimes;
    QSet<View *> listeners; //set容器避免重复
    void notifyListener();
};

#endif // MODEL_H

model.cpp

#include "model.h"

Model::Model()
{
    m_clickTimes = 0;
    notifyListener();
}

int Model::getClickTimes() const
{
    return m_clickTimes;
}

void Model::setClickTimes(int value)
{
    if(m_clickTimes != value)
        m_clickTimes = value;
    notifyListener();
}

void Model::incrementClickTimes()
{
    m_clickTimes++;
    notifyListener();
}

void Model::addListener(View *v)
{
    listeners.insert(v);
    notifyListener();
}

void Model::removeListener(View *v)
{
    listeners.remove(v);
}

void Model::notifyListener()
{
    foreach (View *v, listeners) {
        v->notify();
    }
}

view.h

#ifndef VIEW_H
#define VIEW_H

#include <QPushButton>
#include <model.h>

class Model;

class View : public QPushButton
{
    Q_OBJECT
public:
    explicit View(QWidget *parent = 0);
    void notify();

protected:
    void mouseReleaseEvent(QMouseEvent *e);

private:
    Model *model;
};

#endif // VIEW_H

view.cpp

 

#include "view.h"

View::View(QWidget *parent) :
    QPushButton(parent)
{
    model = new Model();
    model->addListener(this);
}

void View::mouseReleaseEvent(QMouseEvent *e)
{
    model->incrementClickTimes();
}

void View::notify()
{
    setText(QString::number(model->getClickTimes()));
}

 

main.cpp

#include <view.h>
#include <QApplication>


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    View v;
    v.show();
    
    return a.exec();
}

思考:

1.Model类只处理数据,View类处理事件和如何显示程序。

2.Model类中有一个容器 listeners,存放需要显示数据的类,每当应用程序状态改变时(m_clickTimes改变),告诉那些类,应用程序状态改变啦!

3.View类 mouseRelease函数处理事件,notify函数显示数据。

 

posted @ 2017-05-27 22:44  billxyd  阅读(224)  评论(0编辑  收藏  举报