了解MVC模式
我在理解MVC模式方面遇到了一些麻烦。 我明白我们正试图从业务逻辑中分离出GUI,尽pipe我在理解方面存在问题。
从我所了解的View
来看,就是用户所看到的。 所以它通常是窗口/窗体。 Controller
介于View
和Model
。 控制器将使数据在两个方向上“stream动”。 它也将在需要的时候保持状态(如果我有一个5级的向导, Controller
负责确保它们按照正确的顺序进行)。 该Model,
是我的应用程序逻辑的核心所在。
这个观点是否正确?
为了把它变成更有意义的东西,我将尝试用WinForms(没有ASP.NET或者WPF,请示意)绘制一个简单的例子 – 对于java人群,从我所了解的Swing中以相似的方式工作到WinForms的方式!),看看我是否正确,我会提出我一直这样做的问题。
假设我有一个只包含一个类的模型(为了简单起见,我知道这会让这个例子看起来很笨,但是这样做更简单):
class MyNumbers { private IList<int> listOfNumbers = new List<int> { 1, 3, 5, 7, 9 }; public IList<int> GetNumbers() { return new ReadOnlyCollection<int>(listOfNumbers); } }
现在是时候让我的Controller
:
class Controller { private MyNumbers myNumbers = new MyNumbers(); public IList<int> GetNumbers() { return myNumbers.GetNumbers(); } }
该View
应该只有一个ListBox
,其中包含MyNumbers
检索的所有数字。
现在,第一个问题出现了:
Controller
是否应该负责创buildMyNumbers
? 在这个简单的例子中,我认为它是可以接受的(因为MyNumbers
将完全相同,不pipe是什么,也没有关联的状态)。 但是让我们假设我想要使用所有不同的控制器我的应用程序具有相同的MyNumbers
实例。 我将不得不传递给该Controller
(以及所有需要它的其他人)我想要使用的MyNumbers
实例。 谁来负责呢? 在这个WinForms的例子中,这将是View
? 或者这是创buildView
的类?
回答这个问题:这三个部分的实例顺序是什么? 什么是MVC
的“所有者”调用来创build它的代码? Controller
是否应该创buildView
和Model
? 应该实例化Controller
和Controller
Model
?
第二个问题:
假设我只希望我的应用程序具有Use Case
Controller
描述, main
方法应该如何?
第三:
为什么在下面的MVC图中, View
有一个箭头到Model
? Controller
应该始终是View
和Model
之间的桥梁吗?
我还会有一两个问题,但在了解了这个第一个细节之后,可能会有更多的疑问。 或者,也许在我明白了第一个问题之后,所有其他人都会分开。
谢谢!
获得MVC句柄的最简单的方法就是在一个强制执行的框架中使用它。
- 该模型与数据源(数据库或其他)交互,并允许您访问您的数据。
- 该视图与外部世界交互,从某处接收input并将数据传递给控制器,同时监听控制器以确保其显示正确的数据。
- 控制器是所有魔法发生的地方; Controller操纵数据,推送事件,并处理双向(来自/来自视图和来自模型)的变化。
这个图很有帮助(它比维基百科更有意义): MVC图http://java.sun.com/developer/technicalArticles/javase/mvchttp://img.dovov.comFigure4.gif
来源 ,和MVC上的一个伟大的文章!
至于在我的post内的批评,我想我会给我一个post,我倾向于在PHP中创build一个MVC模式
在PHP中,我把框架分成几个部分,在MVC中有一些是正常的。
伯:
- 调节器
- 模型
- 视图
Secondariness – ModelLayer
- ViewLoader
- 图书馆
- ErrorLayer
在控制器内,我通常允许所有访问辅助层以及从主视图查看和模型。
这是我构build它的方式
|---------| |------------| |------------| | Browser | ----> | Controller | ----> | Model | |---------| |------------| |------------| | | | | | | |----------------| | | | |------------| -------------| View | |------------|
在我的图中,我通常绕过View <-> Model
连接并执行Controller <-> Model
,然后从Controller <-> View
的链接分配数据。
在我的框架内,我倾向于创build一个对象存储系统,以便我可以轻松获取对象等等。 我的对象存储的一个例子就是这样
class Registry { static $storage = array(); public static function get($key) { return isset(self::storage[$key]) ? self::storage[$key] : null; } public static function set($key,$object) { self::"storage[$key] = $object; } }
有点更先进的是这个概要,所以当我第一次初始化对象时,我把它们存储为Registry::set("View",new View());
所以总是可以访问的。
所以在我的控制器巫婆是基础控制器我创build了几个神奇的方法__get()
__set()
使任何扩展控制器的类我可以很容易地返回请求例如:
abstract class Controller { public function __get($key) { //check to make sure key is ok for item such as View,Library etc return Registry::get($key); //Object / Null } }
和用户控制器
class Controller_index extends Controller { public function index() { $this->View->assign("key","value"); // Exucutes a method in the View class } }
该模型也将被放置到registry中,但只允许从ModelLayer调用
class Model_index extends ModelLayer_MySql { }
要么
class Model_index extends ModelLayer_MySqli { }
或文件系统
class Model_file extends ModelLayer_FileSystem { }
以便每个类可以具体到存储types。
这不是传统types的MVC模式,但可以称为Adoptive MVC。
其他对象,如View Loader,不应该放在registry中,因为它不是专门为用户兴趣而是被其他实体使用,如View
abstract class ViewLoader { function __construct($file,$data) //send the file and data { //Include the file and set the data to a local variable } public function MakeUri() { return Registry::get('URITools')->CreateURIByArgs(func_get_args()); } }
因为模板文件被包含在View加载器中而不是View类中,所以它将用户方法从系统方法中分离出来,并允许在视图本身中使用方法来获得一般逻辑。
模板文件的示例。
<html> <body> <?php $this->_include("another_tpl_file.php"); ?> <?php if(isset($this->session->admin)):?> <a href="<?php echo $this->MakeUri("user","admin","panel","id",$this->session->admin_uid) ?>"><?php echo $this->lang->admin->admin_link ?></a> <?php endif; ?> </body> </html>
我希望我的例子能帮助你更多地理解这一点。
回答第三个问题 :
当模型改变时,它通知视图,然后视图使用其获取器从模型获取数据。
“从我所了解的视angular来看,就是用户所看到的,所以它一般就是窗口/窗体,控制器位于视图和模型之间,控制器将”处理“两个方向的数据,也将持续状态在需要的时候(如果我有一个5步的向导,控制器的责任是确保它们按照正确的顺序进行),Model是我的应用程序逻辑的核心。
这几乎是正确的。 控制器不保留数据。 它调用一个保存数据的服务。 原因是,坚持数据不只是一个保存的呼叫。 您可能需要对数据进行validation检查,以确保其符合您的业务需求。 您可能需要进行一些身份validation,以确保数据可以由用户保存。 如果你在一个服务中这样做,那么你有一个很好的function,你可以反复使用,比如一个web应用程序和一个web服务。 如果你在一个控制器中做这件事,比如说一个Web应用程序,当你去编写你的Web服务时,你将不得不重构和/或重复代码。
回应你的评论“我不知道我完全理解你的观点,控制器是否检查UIinput,或者是模型吗?
您的控制器应该只控制执行哪些业务functionpath。 那是它的。 控制器应该是编写代码的最简单的部分。 你可以在gui上做一些validation(例如查看,例如确保电子邮件地址格式正确,文本input不超过最大值),但是业务层也应该validationinput – 正如我前面提到的那样,当你开始站起来更多的端点,你不必重构。
财务总监是否应该负责创buildMyNumbers?
我会说' 绝对不是 '。
如果MVC模式被devise为解耦M,V和C元素,那么如果C用new MyNumbers()
简单地实例化M,那么这将如何工作?
在Java中,我们将在这里使用像Spring Framework这样的东西。 您需要一种方法来在configuration文件或其他合适的位置( 即不在编译的代码中)expression依赖关系 – 或者说是如何实现的细节。
但是这个问题还有另外一个元素:你可能不应该用你打算使用的具体的运行时types来定义myNumbers
variables(在C里面)。 使用一个接口或一个抽象类,并保持它的实际运行时types是什么。 这样,将来你可以重新实现IMyNumbers接口,以满足新出现的需求(那些你现在不知道的),你的C组件将继续完美工作,而不是更聪明。
为什么在下面的MVC图中,View有一个箭头到Model? 控制器不应该始终是View和Model之间的桥梁吗?
这是MVC模型2.您通常可以在其中CONTROL执行业务的Java企业应用程序中看到它,以及处理/来自MODEL的数据并select将哪个VIEW回送给客户端。 渲染到客户端时,VIEW将使用来自MODEL的数据:
替代文字http://www.blogjava.nethttp://img.dovov.comblogjava_net/marco/7342/o_2.JPG
这里是一个例子,如何从JSP(VIEW)文件中访问一个bean(MODEL)的数据:
class Person {String name;} // MODEL My name is ${bean.name} // VIEW
这是来自Java,但希望它会有所帮助。
主要的:
public static void main(String[] args) { MyNumbers myNums = new MyNumbers(); // Create your Model // Create controller, send in Model reference. Controller controller = new Controller(myNums); }
您的控制器需要参考您的模型。 在这种情况下,控制器实际上创build了所有的Swing组件。 对于C#,您可能希望在此处保留表单初始化,但View / Form需要对Model(myNums)和Controller(控制器)的引用。 希望有一些C#人员可以在这方面提供帮助。 视图还需要注册为模型的观察者(请参阅观察者模式)。
这里是我有的构造函数(根据你的情况调整):
public NumberView(Controller controller, MyNumbers myNums) { this.controller = controller; // You'll need a local variable for this this.myNums = myNums; //You'll need a local variable for this myNums.registerObserver(this); // This is where it registers itself }
视图将工作传递给控制器来处理用户的操作(button等等)。 控制器决定在模型中调用/做什么。 一般来说,模型会做一些事情并改变它的状态(也许更多的数字在你的列表中,无论它做什么)。 在这一点上,该模型将让其观察员知道它已经改变并更新自己。 然后视图去获取新的数据并自行更新。 这就是为什么模型和视图谈话(你的第三个问题)。
所以模型将有:
public void notifyObservers() { for (Observer o: observers) { o.update(); // this will call the View update below since it is an Observer } }
所以在视图中,你会有这样的东西:
public void update() { setListBox(myNums.getNumbers()); // Or whatever form update you want }
希望有所帮助。 我知道这是Java,但这个概念仍然适用。 你必须做一些Observer模式的阅读才能完全获得它。 祝你好运!
我会试着从相对较less的技术支持来回答这个问题。 我会尝试通过一个一般的例子。
Controller
控制使用哪个view
。 所以,比如说,如果你正在写页面, controller
会引导你进入input view
(比如说),而如果你正在阅读相同的页面,它会引导你到它的success view
(比如说)。
在写入页面之后, controller
将把这些parameter passing给相关的model
,在这个model
中,关于必须完成的逻辑与之相关。 如果出现错误,则controller
将引导您进入error view
。
我的知识基于我在Agavi一个月的经验。 希望这可以帮助。
- 视图绘制模型并将其呈现给用户
- 控制器处理用户input并将其转换为模型中的修改
- 模型保存数据和修改逻辑
把它翻译成代码没有意义。 无论如何你都不会正确地得到它。
视图
-
用户界面/负责input输出/一些validation/需要有一种方式来通知外界的UI级事件
-
只知道模型
模型
- 数据结构/表示所呈现的数据/不应该包含业务逻辑(可能最多只有一些数据/结构validation)
- 只知道自己(想想一个Person类只有Name和Age)
调节器
-
负责业务逻辑/它包装视图和粘贴各自的模型到他们/必须能够响应查看事件/访问应用程序的其他层(持久性/外部服务/业务层等)
-
知道一切(至less是视图和模型),并负责将所有东西粘合在一起