【问题标题】:Model View Controller Design pattern Code Example模型视图控制器设计模式代码示例
【发布时间】:2011-04-28 09:51:57
【问题描述】:

我正在研究模型-视图-控制器设计模式,我从理论上理解了该模式背后的概念,但我想看看如何将其付诸实践。
Wikipedia 提到了 Wt - Web 工具包、CppCMS 和其他一些使用该模式的标准实现,但是我并不熟悉这些,我只是希望和 如果有人可以提供一些示例代码(希望是 C++)来实现该模式并解释该模式的理论被付诸实践,将不胜感激。

【问题讨论】:

    标签: c++ design-patterns oop


    【解决方案1】:

    可以基于 MVC 设计一个简单的文本编辑器。将string 类视为存储数据的模型。我们可能有一个名为SimpleTextView 的类,它按原样显示附加到它的string 中的文本。一个名为KeyboardEventHandler 的类可以充当控制器。控制器将通知视图有关新的键盘事件。视图反过来修改模型(如附加或删除文本)。模型中的更改会反映在附加到它的所有视图上。例如,可能有另一个名为HtmlView 的视图附加到从SimpleTextView 中操作的string 对象。如果用户在SimpleTextView 中输入有效的HTML 标签,HtmlView 将实时显示格式化输出。

    【讨论】:

      【解决方案2】:

      在我编写的 Python 3.x 编程介绍的第 2 章中,有几个完整的 MVC 示例和讨论(我还没有完成第 3 章等,该项目已经搁置了一段时间 - - 当我发现我写 Python 可能不适合非常大规模的开发时,Python 社区真的很喜欢愤怒的蜜蜂群,因此很难获得明智的反馈)。可从Google Docs 获取 PDF 格式。我不知道它与常见的 MVC 实现的映射情况如何,我主要关心的是如何理解总体思路。 :-)

      干杯,

      PS:PDF 文件中有一个很好的目录,但 Google Docs 没有显示它。您需要 dl 并使用 Foxit 或 Acrobat 或其他一些 PDF 查看器。我认为 Google Docs 上有一个单独的可查看目录,但尚未检查,也不记得是否更新了。

      PPS:忘了提一下,接近结尾的 MVC 图像处理示例有 Lena Söderberg 的漂亮图片! :)

      【讨论】:

        【解决方案3】:

        这是我做的一个简单的例子(没有尝试编译它,如果有错误请告诉我):

        class Button; // Prewritten GUI element
        
        class GraphGUI {
        public:
            GraphGUI() {
                _button = new Button("Click Me");
                _model = new GraphData();
                _controller = new GraphController(_model, _button);
            }
            ~GraphGUI() {
                delete _button;
                delete _model;
                delete _controller;
            }
        
            drawGraph() {
                // Use model's data to draw the graph somehow
            }
            ...
        
        private:
            Button*              _button;
            GraphData*           _model;
            GraphController*     _controller;
        };
        
        class GraphData {
        public:
            GraphData() {
                _number = 10; 
            }
            void increaseNumber() {
                _number += 10;
            }
            const int getNumber() { return _number; }
        private:
            int _number;
        };
        
        class GraphController {
        public:
            GraphController(GraphData* model, Button* button) {
                __model = model;
                __button = button;
                __button->setClickHandler(this, &onButtonClicked);
            }
        
            void onButtonClicked() {
                __model->increaseNumber();
            }
        
        private:
            // Don't handle memory
            GraphData*    __model;
            Button*       __button; 
        };
        

        忽略 Button 的实现,基本上这个程序会使用 GraphGUI 来显示一个在按下按钮时会发生变化的图形。假设它是一个条形图,它会变得更高。

        由于模型独立于视图(按钮),而控制器处理两者之间的通信,这遵循 MVC 模式。

        当按钮被点击时,控制器通过 onButtonClicked 函数修改模型,Button 类知道在被点击时会调用该函数。

        这样做的美妙之处在于模型和视图是完全独立的,每个的实现都可以发生巨大变化并且不会影响另一个,控制器可能只需要进行一些更改。如果这种情况下的模型根据一些数据库数据计算出一些结果,那么单击按钮可能会导致这种情况发生,但按钮实现不必更改。或者,当点击发生时,它可以告诉控制器鼠标悬停在按钮上时,而不是告诉控制器。无论是什么触发了更改,都会对模型应用相同的更改。

        【讨论】:

        • 在 MVC 中,视图通常不知道控制器。通常,控制器会知道模型和视图,并会为视图提供模型的适当实例。正如您所提到的,模型将不知道视图。
        • @Matt,robdev :模型不知道视图,但模型可以在其数据中提示更新视图..(观察者模式的典型用法)
        • @Matt,我明白你的意思,但在这个例子中,视图并没有明确地知道控制器。它只是给了一个对象和函数指针,并说“不管你是谁,我只是被点击了!调用你的函数”,然后调用 onButtonClicked()。
        • 如果有一个“绘制图形”按钮将触发GraphGUI::OnButtonClick() 函数,以及一个带有GraphGUI::ShowMessage() 的消息面板,它应该显示文本“绘制图形...” ,在哪种情况下会调用GraphGUI::ShowMessage() 函数? 1)GraphGUI::OnButtonClick()直接调用GraphGUI::ShowMessage()。 2) GraphGUI::OnButtonClick() 调用GraphController::onButtonClicked(),然后GraphController::onButtonClicked() 调用GraphGUI::ShowMessage()
        • 不会编译:参见_button vs __button 等,后者不能用作保留相邻下划线的标识符。此外,GraphGui 似乎存在身份危机。是图形用户界面吗?然后它是一个视图,不应该拥有/知道模型/控制器。然而,它似乎试图同时成为控制器的一部分并拥有“其他”控制器和模型——更糟糕的是——通过动态分配和原始new/delete,这很可能是不必要的。对我来说(A)所有权根本不是必需的,但是(B)如果有原因,它一定不能由 View 完成,只能由 Controller 完成
        【解决方案4】:

        代码是理解和学习模型视图控制器的最佳途径:

        这是一个简单的 JS 示例(来自Wiki

        /** Model, View, Controller */
        var M = {}, V = {}, C = {};
        
        /** Model stores data */
        M.data = "hello world";
        
        /** View controls what to present */
        V.render = (M) => { alert(M.data); }
        
        /** Controller bridges View and Model */
        C.handleOnload = () => { V.render(M); }
        
        /** Controller on Windows OnLoad event */
        window.onload = C.handleOnload;
        

        这是 C/C++ 的详细帖子 Model-View-Controller Explained in C++

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-09-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-12
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多