C++ 设计框架注意的地方

左心房为你撑大大i 提交于 2020-01-25 09:20:24

C++ MVC 注意的地方

工作快两年了,之前写了第一篇博客(拢共就没有多少字,也好意思说是博客。。。),正好趁着这个机会总结下吧。
毕业去了深圳某激光公司当一个小码农,庆幸遇到了一个人非常好的组长,带着我在这行扎下了脚,感谢我强哥当初毫不吝啬的指导(就不知道茫茫大海你能不能看到我这篇),才能让我今天能够有*xue微的资格谈谈设计。
现在在一家小公司,算是项目负责人了吧(-__-),公司刚成立没多久,啥底层库没有,项目也是我入职了才启动,整个框架包括功能实现都是我自己完成(框架已经搭完,功能也实现了大半了),这段时间累不累?真的累,但是感觉嘛?996福报是真的爽!
好了废话不多说了,让我们进入主题。


MVC

啥是MVC?
M --Model 模型
V --View 视图
C – Controller 控制器

很多同学对MVC一知半解,窃以为还是对项目流程不够熟悉,甚至只是停留在网上的相关资料,这就造成了感觉自己好像是看明白,但又好像不那么明白,仿佛是有一层薄薄的面纱挡在跟前,能够看个大概,却不能够清楚细节。
下面就让我们来一起揭开这层讨厌的面纱。
百度搜一下,会发现对于MVC网上有各种解说,怎么说呢,所谓一千个观众就有一千个哈莫雷特(好像是这么说的吧)。首先盗几个图:
图一:
在这里插入图片描述
图二:
在这里插入图片描述
图三:
在这里插入图片描述
图四:
在这里插入图片描述
这只是我简单的从网上随手拿来的,从这可以看出不同的人眼中有着不同的MVC模式,下面我们来谈谈关于mvc具体点的东西。
MVC是什么?MVC用来干什么?
我觉得MVC很像三层架构,注意我的用词,我只是说了很像,但是并不是“就是”!MVC通过将视图(View)、业务逻辑、数据分割开,来实现视图与数据操作(即业务逻辑)分离的目的,那么是通过什么分割的呢?
答案就是Controller,即控制器,也就是说原则上view是不能够与model层进行直接交互,业务生产中产生交互也应该是通过controller来实现,即便是有直接的交互也不应该使用直接调用的方式,即在view层中直接调用model层中的类来进行业务逻辑操作或者是在model层中调用view层的类来进行页面刷新,原因:要做到低耦合甚至是零耦合,即理想的状态下,view层和model层都是能够单独拿出来二不会影响到另一方的功能实现。

但是某些情况下,让view层和model层直接交互会比通过controller层方便的多,而我们又不想违背mvc的原则,怎么办呢?这时我们就要引入一种设计模式了------观察者模式!对观察者模式不了解的同学自行百度,这里我就不延伸了。
为什么要用到这种模式呢?答案就是“王不见王”,简单来讲就是你不知道我的存在,我也不知道你的存在的效果。
插播一条我理解的MVC
在这里插入图片描述
从图中可以看到view和model之间的联系主要是通过中间的controller来实现的,上下两条红色的线就是我后面要说的重点了。
qt的信号槽机制就是基于观察者模式,下面我们就通过对Qt的信号槽的解读来说明。
个人理解信号槽的精髓就是:
发送方:我不管谁能用到我的信息,我只管发出去,谁用谁自己来收。
接收方:我不管你是谁,我只知道这条信号我用得着,那我就拿来用。
对,就是那么霸道,又那么理所当然。
上面的图四是取自百度百科的图,我们可以看到view和model之间是存在联系的,两者交互的区别在于一个是方法调用,一个是事件,方法调用就不多说了,重点说说事件,这里的事件就是我说的信号,由model方发送一个信号,即事件,view方接收这个信号(或者说捕捉到这个事件),再进行相应的刷新操作。
声明
对百度百科所说的view通过方法调用的方式对model进行状态查询这种操作,我不认同,有方法调用就涉及到model逻辑层的类,我个人认为这是违背了MVC的原则。(当然也有可能是我功夫没到家,理解有误,但是我至少目前来讲我是这么认为的)。

废话不多说了,接着上干货,套入实际情况来考虑,
在这里插入图片描述
现在view有两个数据A和B,用户想通过点击按钮来获取两者的和C,这个求和的过程就是我们指的业务逻辑,如果在按钮caculate的槽函数中直接将A和B相加,再将结果显示在C中,这种就违背了MVC的原则,为什么呢?
因为业务逻辑model和页面view产生了交叉(或者说是业务逻辑model直接存在了view中),可以假设一下,加入此时的业务逻辑足够庞大,后期需要变动业务逻辑或者页面的显示方式会产生什么影响?
那要实现业务与显示分离怎么做到呢?
1.用户请求通过点击按钮传给控制器,

//view 
class MainWindow2 : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow2(QWidget *parent = 0);
    ~MainWindow2();

private:
    void setItemText(int total); //填写结果C的数值

private slots:
    void slot_caculate(); //按钮槽函数

private:
    QLabel *m_labelA;
    QLabel *m_labelB;
    QLabel *m_labeltotal;
    QLineEdit * m_lineditA;
    QLineEdit *m_lineditB;
    QLineEdit *m_linedittotal;
    QPushButton * m_calculate;

    Manager2 manager2;//控制器
};
void MainWindow2::slot_caculate()
{
    bool ok;
    setItemText(manager2.get_caculateNum(m_lineditA->text().toInt(&ok), m_lineditB->text().toInt(&ok)));
    ///页面调用控制器方法获取结果,而结果是怎么来的,页面并不知道
}

当点击了按钮,view拿到用户的请求,由view调用控制器取得view的参数交给model层进行逻辑运算,将运算后的结果在交给view进行显示。

int Manager2::get_caculateNum(int a, int b)
{
    return caculate.add(a, b);
}

在这个过程中,只有控制器参与了整个过程,即控制器知道A和B从什么地方来,要到什么地方去,但是控制器即代码中的manager2 并不对A、B和结果进行操作,只是起到传递view和model之间的消息的作用。
可以看到view层并不知道自己的A、B给到了谁(或者说知道A、B给到了manager2, 但是并不关心谁对A、B进行了运算),而model层即代码中的caculate也不知道自己运算后的结果被用作何处。
这个过程是我画的图的中间一条路径
在这里插入图片描述
2.然后再来看看另外两条红线表示的路径
声明一点,我建议view和model层之间如果一定要有直接交互(不排除有些业务逻辑两者直接交互会产生很大便捷,所以要直接交互),那么我建议这种情况最好是通过事件或者我们所说的信号来进行交互。

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    
    MainWindow window;
    w.setWindowTitle("this is second way");
    Caculate caculate;
    QObject::connect(&w, &MainWindow::sgl_caculate2, &caculate, &Caculate::slot_multiplication);
    QObject::connect(&caculate, &Caculate::sgl_num, &w, &MainWindow::setItemText2);
    w.show();

    return a.exec();
}

可以看到在mian()函数里面只有两个类,一个是view的Mainwindow,另一个就是model的caculate,来解读一下,当用户点击按钮的时候,view发出一个信号sgl_caculate2,我们将这个信号和caculate的slot_mutiplication槽函数进行连接(__ 对这里我又变成了求积了,哈哈),也就是说一旦用户点击了按钮,view层就会将a、b以信号的方式发射出去,至于谁要接收这个,view自身是不考虑的。
而当model层的caculate捕捉到了这个信号之后,会进行相应的业务运算,再将运算后的乘积,同样以信号的方式发射出去,再由view层捕获进行相应的显示,在这个过程中view层不知道结果是层哪儿来的,甚至不知道结果是经过了什么运算(求和变成了求积都不知道,还真是个小糊涂蛋)。
重点来了,可能有同学会有疑惑了?
这只有model层和view层啊,怎么没有controller的存在呢?
眼光不要放得那么狭隘吗,作为一名合格的程序员,要有大局意识,才能担任的起框架性设计的重任,来,让我们蹦出来看一看,view(window)和model(caculate)是在哪里被绑定在一起的?
答案是main()函数。
对喽,这里的main函数就看做是一个controller,也就是他知道哪个信号代表什么意思,应该把这个信号给到谁,这不就是控制器的作用吗?
当然了,这只是为了便于同学们好理解,将main函数进行了抽象,真正项目中可不会把这些都放在main()里面,这一个项目下来得有多少东西要往里面写啊。

后记
项目中,切勿生搬硬套,要学会灵活运用,毕竟一个项目里面model,view,controller都不会是只有一个的,至于怎么去使用就要看具体的项目了,上面的代码源码(源码三个实现方式,写的太多了,实在不接着想写了,快9点了,要下班回去睡觉觉了)放在这里,有需要的同学可以自行下载。
后面抽时间会再接着补充。
链接:
https://download.csdn.net/download/ta_123123/12093272

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!