MVC in MFC or WTL - yinxufeng - 博客园
MVC in MFC or WTL - yinxufeng - 博客园
关于MVC
MVC是一种分离用户界面和业务逻辑的开发架构。
● 模型(Model):体现应用程序业务信息(数据)和业务数据的处理。所有有关数据库的操作只限制在该模型中。
● 视图(View): 代表用户交互界面
● 控制器(Contrlloer):控制器负责接收、截取用户请求(如键盘输入,鼠标点击),但不处理业务信息,它只把用户的信息传递给模型,告诉模型该做什么,由模型返回最终的处理结果。控制器再选择符合要求的视图返回给用户。背景
做Web或者Java的对MVC会比较熟悉,对于用MFC开发桌面应用程序的developer来说,已经习惯于拖一个按钮,然后双击,在CxxxDlg.cpp中添加事件响应。随着业务逻辑的复杂,这一个文件包含了所有的界面代码,逻辑处理,数据操作…。频繁的界面修改可能会破坏比较稳定的业务代码。将业务逻辑分离出来,由一个控制器负责,就可以避免这种干扰。
去搜索了下MVC在桌面应用程序开发上的资料,找出两篇:
1. vckbase上的,采用MFC编制MVC模式之球体演示程序。处理流程:Controller(CMVCSphereDlg)捕获后用户输入后通知Model(CSphere),Model再通知两个View(TextView & CGraphicView)更新显示。由模型通知视图刷新
2. codeproject上的,Simple Example of MVC (Model View Controller) Design Pattern for Abstraction。处理流程:View(frmCalcView)捕获用户事件后传递给Controller(CalcController), Controller调用Model(CalculatorModel)的运算方法得到计算结果,再回传给View更新显示。由控制器通知视图刷新看完这两个已经搞不定到底哪种才是真正的MVC,后来又查了资料说:
MVC模式有许多变体。第一种,由模型通知视图刷新,称为主动MVC;如果由控制器更新模型以后通知视图,称为被动MVC结构。在许多应用中,没有明显的控制器角色,也没有视图嵌套。可见根据实际需要,构成MVC的三个模式上都可能出现变化。Web浏览器就是被动MVC结构的一个实例。实践
我将上面第二个用C#写的计算器的例子,改用WTL作为界面库,采用MVC架构设计。(据说MVC不适合小中型引用程序,多大才算中小呢?只有自己去开发体会了)
先来看下代码结构:
Model,View,Controller分开,Resource存在一些资源文件。1. 先来看下App类,怎么将三者组织起来的
1: CMessageLoop theLoop;2: _Module.AddMessageLoop(&theLoop);3:4: // View5: CMainDlg dlgMain;6: if(dlgMain.Create(NULL) == NULL)7: {8: ATLTRACE(_T("Main dialog creation failed!\n"));9: return 0;10: }11: // Model12: CalcModel* pModel = new CalcModel();13: // Controller14: CalcController* pController = new CalcController(pModel, &dlgMain);15:16: dlgMain.ShowWindow(nCmdShow);17:18: int nRet = theLoop.Run();19:20: _Module.RemoveMessageLoop();21:22: // 先析构哪个呢?23: delete pController;24: delete pModel;2. CalcController类构造函数需要传递Model和View的指针,接收从View传递来的用户事件,然后调用Model和View中中方法来完成用户请求。
1: // 运算控制器2: //3: ///4: #ifndef _CALCCONTROLLER_H_5: #define _CALCCONTROLLER_H_6:7: #include "CalcView.h"8: #include "CalcModel.h"9:10: class CalcController11: {12: protected:13: CalcModel* m_pCalcModel;14: CalcView* m_pCalcView;15:16: public:17: CalcController(CalcModel* pModel, CalcView* pView)18: : m_pCalcModel(pModel) // Model19: , m_pCalcView(pView) // View20: {21: ATLASSERT(m_pCalcView);22: ATLASSERT(m_pCalcModel);23: m_pCalcView->AddController(this); // 将controller传给view24: }25:26: // ......省略部分代码27:28: // 用户点击数值(0~9)29: virtual void ClickValue(double dValue)30: {31: // ......省略32:33: // 生成新操作数34: CString strValue;35: strValue.Format(_T("%g"), dValue);36: m_strOperateValue += strValue;37:38: m_clickType = click_value;39: m_pCalcView->ShowOperateResult(m_strOperateValue);40: }41:42: // 用户点击操作(+, -, *, ÷)43: virtual void ClickOperate(OPERATE_TYPE op_type)44: {45: // ......省略46:47: // 计算出上一次运算符的结果48: double dResult;49: dResult = m_pCalcModel->Calc(m_operaType, _tstof(m_strOperateValue));50: CString strResutl;51: strResutl.Format(_T("%f"), dResult);52: strResutl.TrimRight('0');53: strResutl.TrimRight('.');54:55: // 更新view56: m_pCalcView->ShowOperateExpression(m_strExpression);57: m_pCalcView->ShowOperateResult(strResutl);58:59: // ......省略60: }61:62: // ......省略63: };64:65:66: #endif // _CALCCONTROLLER_H_注意到,在Controller中,View和Model是没有直接交互的。通过在Controller中调用View的方法(ShowOperateResult,ShowOperateExpression)来更新View中的显示。那么View又是怎么传递用户事件给Controller的呢?
3. 通过m_pCalcView->AddController(this) 将Controller传给View。View就可以在接收到用户请求之后,就可以调用Controller中的事件处理函数(ClickValue,ClickOperate)
1: class CalcView2: {3: public:4: CalcView()5: : m_pCalcController(NULL)6: {7: }8:9: void AddController(CalcController* pController)10: {11: ATLASSERT(pController);12: m_pCalcController = pController;13: }14:15: // interface16: // 显示运算表达式17: virtual void ShowOperateExpression(CString strExpression) {}18: // 显示运算结果19: virtual void ShowOperateResult(CString strResutl) {}20:21: protected:22: CalcController* m_pCalcController;23: };CMainDlg从CalcView继承,重载接口实现计算结果的显示。MVC的一个目标就是把用户界面分离,如果要换一个界面,或者改用MFC编写界面了,只需要重载接口改变显示方式而已。
1: class CMainDlg : public CDialogImpl<CMainDlg>2: , public CUpdateUI<CMainDlg>3: , public CMessageFilter4: , public CIdleHandler5: , public CalcView6: {7: public:8: // ......省略9:10: BEGIN_MSG_MAP(CMainDlg)11: MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)12: COMMAND_ID_HANDLER(IDC_BUTTON_VAULE0, OnClickValue)13: COMMAND_ID_HANDLER(IDC_BUTTON_VAULEP, OnClickDecimalPoint)14: COMMAND_ID_HANDLER(IDC_BUTTON_ADD, OnClickOperate)15: // ......省略16: END_MSG_MAP()17:18: //19: LRESULT OnClickValue(WORD, WORD , HWND hWndCtl , BOOL&)20: {21: CString strValue;22: ::GetWindowText(hWndCtl, strValue.GetBuffer(1), 2);23: strValue.ReleaseBuffer();24:25: m_pCalcController->ClickValue(_tstof(strValue));26:27: return 0;28: }29:30: LRESULT OnClickDecimalPoint(WORD, WORD , HWND , BOOL&)31: {32: m_pCalcController->ClickDecimalPoint();33: return 0;34: }35:36: LRESULT OnClickOperate(WORD, WORD wID, HWND , BOOL&)37: {38: switch (wID)39: {40: case IDC_BUTTON_ADD:41: m_pCalcController->ClickOperate(OP_ADD);42: break;43: case IDC_BUTTON_SUB:44: m_pCalcController->ClickOperate(OP_SUB);45: break;46: case IDC_BUTTON_MULT:47: m_pCalcController->ClickOperate(OP_MULT);48: break;49: case IDC_BUTTON_DIVE:50: m_pCalcController->ClickOperate(OP_DIVE);51: break;52: }53:54: return 0;55: }56:57: //58:59: // Override60: void ShowOperateResult(CString strResutl)61: {62: GetDlgItem(IDC_STATIC_RESULT).SetWindowText(strResutl);63: }64:65: void ShowOperateExpression(CString strExpression)66: {67: GetDlgItem(IDC_STATIC_EXPRESSION).SetWindowText(strExpression);68: }69: };4. 最后看一下Model类,只负责数值计算,以及返回运算结果
1: class CalcModel2: {3: public:4: CalcModel() : m_dResult(0)5: {6: }7:8: // 执行计算,返回计算结果9: double Calc(OPERATE_TYPE op_type, double dValue)10: {11: switch ( op_type )12: {13: case OP_NULL: // 第一个操作数默认执行和0相加14: case OP_ADD: // 加法15: Add(dValue);16: break;17: case OP_SUB: // 减法18: Sub(dValue);19: break;20: case OP_MULT: // 乘法21: Mult(dValue);22: break;23: case OP_DIVE: // 除法24: Dive(dValue);25: break;26: }27:28: return m_dResult;29: }30:31: protected:32: // 加33: void Add(double dValue)34: {35: m_dResult += dValue;36: }37:38: // 减39: void Sub(double dVaule)40: {41: m_dResult -= dVaule;42: }43:44: // 乘45: void Mult(double dVaule)46: {47: m_dResult *= dVaule;48: }49:50: // 除51: void Dive(double dVaule)52: {53: m_dResult /= dVaule;54: }55:56: protected:57: double m_dResult; // 结果58: };完整代码:MVC in MFC or WTL
MVC in MFC or WTL - yinxufeng - 博客园相关推荐
- Asp.net MVC 仿照博客园的简单网站首页 列表设计
本来我打算采用ajax提交请求,异步的请求获取数据,但是我发现如果这样的话就会拖慢开发的进度,拖长时间.所以在这篇博客中仿照首页的列表设计其实和左侧列表网站分类采用了同样的方式,通过局部视图的方式呈现 ...
- Spring MVC + Hibernate JPA + Bootstrap 搭建的博客系统
Spring MVC + Hibernate JPA + Bootstrap 搭建的博客系统 Demo 相关阅读: 1.Spring MVC+Hibernate JPA+ Bootstrap 搭建的博 ...
- 我的架构设计~用层关系图说说mvc,mvvm,soa,ddd - 张占岭 - 博客园
我的架构设计~用层关系图说说mvc,mvvm,soa,ddd - 张占岭 - 博客园
- 博客园山寨版(asp.net mvc 开源)
一 源码地址 github:https://github.com/songboriceboy/cnblogsbywojilu 二 网站实例 www.douyuehan.com 三 技术选型 采用woj ...
- Python爬虫入门教程 54-100 博客园等博客网站自动评论器
爬虫背景 爬虫最核心的问题就是解决重复操作,当一件事情可以重复的进行的时候,就可以用爬虫来解决这个问题,今天要实现的一个基本需求是完成"博客园" 博客的自动评论,其实原理是非常简单 ...
- 如何高效的利用博客园?
写在前面 在河南工作那会儿,虽然遇到问题也百度过,google过,但是很少留意内容来自哪个网站,也许是工作的内容太简单了,也许是太单调了,之后的之后就很少上网查东西了,因为模块相似,功能相似,代码写了 ...
- (转)利用快速开发框架,快速搭建微信浏览博客园首页文章
原文地址:http://www.cnblogs.com/inday/p/weixin-publicf-platform-cnblogs.html 这几天接连发布了<快速开发微信公众平台框架--- ...
- 接口应用小玩具-博客园积分排名变动监控工具
小玩具-博客园积分排名变动监控工具 一个简单的在线服务监控和提醒工具 1 概述 前段时间自己准备重新开启自己的博客园,然后还和一些圈子里面的朋友夸下海口,自己要开始像打游戏那样,进行博客园的 天梯 ...
- 博客园电子月刊[第一期]
本版改进: 简化布局,使之更整洁. 由于客户端邮件不支持图片,去除了一些图片. 由于衡量文章标准不统一,去掉了推荐指数. 规范了文章的分类标准. 增加了作者博客链接,增强互动性. 提供订阅和退订服务. ...
最新文章
- java什么时候用链表,java - 手写LRU(使用链表,时间复杂度O(n))
- hdu 2013 蟠桃记-递推-[解题报告]C++
- Chrome DevTools 之 Network,网络加载分析利器
- 今年四月份,发现我的文章被人全部复制了,抄到博客园了,连原文出处都没有,就算你写个参考文章也行呀
- 不属于jsp构成元素_JSP构成元素-JSP基础
- Kotlin — 适用于原生
- 拓端tecdat|python主题LDA建模和t-SNE可视化
- Android模拟器哪个稳定,哪个安卓模拟器好 什么安卓模拟器稳定流畅速度快不卡顿...
- MSP430 单片机 读取 程序 LM75A LM75 温度传感器
- C语言头歌educoder实训作业答案分享 指针(一)
- C#WPF内存回收与释放LierdaCracker
- AutoIT - 加域工具
- SICP练习题1.14
- 修改DarkNet的weights文件以编辑模型版本号
- MatlabR2018aWin 安装教程 (附文件)
- c语言mfc怎么插入背景图片,MFC 对话框添加背景图片详细过程(两种方法)
- 微信扫码登录,微信公众号生成二维码,关注登录nodejs+vue
- 光模块COB工艺之耦合激光焊
- 天猫双十一狂抢优惠券?机智的程序猿这么玩
- 麦克风离计算机主机多远,直观:您对计算机麦克风的设置和使用了解多少?
热门文章
- JVM学习笔记之-JVM性能监控-JVM监控及诊断工具-命令行方式
- 下一个更大元素 I(LeetCode 496)
- ps -ef | grep 查看进程命令
- 2017-7-22 NOIP模拟赛
- 如何简单的测试kubernetes的dns add-ons是否工作正常?
- MongoDB--架构搭建(主从、副本集)之副本集
- redis 事务,持久化,日志,主从,VM
- #589. 图图的游戏
- 一队老耗子,每个月都生一对小耗子,小耗子长3个月,第四个月开始变成老耗子开始生, 		// 假设所有耗子都不死,请问20个月之后共有多少只耗子?...
- vs code 快捷键设置 2018