首页IT科技mvc nj(MVC in MFC or WTL yinxufeng 博客园)

mvc nj(MVC in MFC or WTL yinxufeng 博客园)

时间2025-05-03 11:15:27分类IT科技浏览2838
导读:关于MVC...

关于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: // View 5: CMainDlg dlgMain; 6: if(dlgMain.Create(NULL) == NULL) 7: { 8: ATLTRACE(_T("Main dialog creation failed!\n")); 9: return 0; 10: } 11: // Model 12: CalcModel* pModel = new CalcModel(); 13: // Controller 14: 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 CalcController 11: { 12: protected: 13: CalcModel* m_pCalcModel; 14: CalcView* m_pCalcView; 15: 16: public: 17: CalcController(CalcModel* pModel, CalcView* pView) 18: : m_pCalcModel(pModel) // Model 19: , m_pCalcView(pView) // View 20: { 21: ATLASSERT(m_pCalcView); 22: ATLASSERT(m_pCalcModel); 23: m_pCalcView->AddController(this); // 将controller传给view 24: } 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: // 更新view 56: 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 CalcView 2: { 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: // interface 16: // 显示运算表达式 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 CMessageFilter 4: , public CIdleHandler 5: , public CalcView 6: { 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: // Override 60: 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 CalcModel 2: { 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 声明:本站所有文章,如无特殊说明或标注          ,均为本站原创发布               。任何个人或组织               ,在未征得本站同意时     ,禁止复制               、盗用     、采集          、发布本站内容到任何网站               、书籍等各类媒体平台               。如若本站内容侵犯了原著者的合法权益          ,可联系我们进行处理。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
css定位有哪些(CSS中常用的几种定位方式) python中int的含义(python中的int是什么意思)