我在理解MVC模式时遇到了一些麻烦。我确实理解我们正试图将GUI与业务逻辑分离,尽管我在理解方法时遇到了问题。
据我所知,View
是用户看到的内容。所以它通常是窗口/窗体。 Controller
位于View
和Model
之间。控制器将使数据在两个方向上“流动”。它还会在需要时保持状态(如果我有一个包含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
是否应负责创建MyNumbers
?在这个简单的例子中,我认为它是可接受的(因为MyNumbers
将完全相同,无论如何,并且没有相关的状态)。但是我们假设我想要用于所有不同的控制器,我的应用程序具有相同的MyNumbers
实例。我必须传递给Controller
(和所有其他需要它的人)我要使用的MyNumbers
实例。谁将对此负责?在这个WinForms示例中,那会是View
吗?或者那是创建View
?
转过来问题:这3个部分的实例化顺序是什么? MVC
的“所有者”要求创建它的代码是什么?
Controller
是否应同时创建View
和Model
? View
是否应实例化Controller
和Controller
Model
?
main
方法应该是什么样子,假设我只希望我的应用程序使用Use Case
这个Controller
描绘?
为什么在以下MVC图表中View
有箭头指向Model
? Controller
不应始终是View
和Model
之间的桥梁吗?
我还有一两个问题,但在我理解了第一个细节后,他们可能会更有意义。或者也许在我明白第一个问题之后,其他所有人都会分崩离析。
谢谢!
答案 0 :(得分:26)
获得MVC处理的最简单方法是在一个强制执行它的框架中使用它,这就是说..
这个图非常有用(它比维基百科更有意义): MVC Diagram http://java.sun.com/developer/technicalArticles/javase/mvc/images/Figure4.gif
Source,以及关于MVC的精彩文章!
答案 1 :(得分:3)
至于我帖子中的批评,我想我会发一篇关于我如何用PHP创建MVC模式的帖子
在PHP中,我将框架分为几个部分,其中有些部分在MVC中是正常的。
<强>初选:强>
<强> Secondariness 强> - ModelLayer
在控制器中,我通常允许所有访问辅助层以及从主要访问视图和模型。
这是我构建它的方式
|---------| |------------| |------------|
| Browser | ----> | Controller | ----> | Model |
|---------| |------------| |------------|
| | | |
| | |----------------|
| |
| |------------|
-------------| View |
|------------|
在我的图表中,我通常会绕过View <-> Model
连接并执行Controller <-> Model
,然后Controller <-> View
的链接会分配数据。
在我的框架中,我倾向于创建一个对象存储系统,以便我可以轻松地获取对象等等。我的对象存储的一个例子是这样的
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());
,以便始终可以访问。
所以在我的控制器中,巫婆是基本控制器,我创建了几个魔术方法__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
}
}
该模型也将被置于注册表中,但只允许从ModelLayer
调用class Model_index extends ModelLayer_MySql
{
}
或
class Model_index extends ModelLayer_MySqli
{
}
或文件系统
class Model_file extends ModelLayer_FileSystem
{
}
这样每个类都可以特定于存储类型。
这不是传统类型的MVC模式,但它可以称为Adoptive MVC。
其他对象(例如View Loader)不应放入注册表中,因为不是专门针对用户的兴趣,而是由其他参与者使用,例如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>
我希望我的例子可以帮助你理解这一点。
答案 2 :(得分:2)
回答第三个问题:
当模型更改时,它会通知视图,然后视图使用其getter从模型中获取数据。
答案 3 :(得分:1)
“根据我的理解,视图,是用户看到的。所以它通常是窗口/窗体。控制器位于视图和模型之间。控制器将”处理“两个方向的数据。它将在需要时也保持状态(如果我有一个包含5个步骤的向导,那么控制器负责确保它们以正确的顺序制作,等等。)模型,是我的应用程序逻辑的核心所在。“
这几乎是正确的。控制器不会保留数据。它调用一个持久保存数据的服务。原因是,持久化数据绝不仅仅是对保存的调用。您可能希望对数据进行验证检查,以确保根据您的业务需求保持理智。您可能需要进行一些身份验证以确保用户可以保存数据。如果您在服务中执行此操作,那么您可以反复使用一组很好的功能,例如Web应用程序和Web服务。如果您在控制器中执行此操作,例如对于Web应用程序,则在您编写Web服务时,您将不得不重构和/或复制代码。
回应你的评论“我不确定我是否完全明白你的意思。控制器是否检查了UI输入,或是模型是否能够完成?”
您的控制器应该只控制执行哪些业务功能路径。多数民众赞成。控制器应该是编写代码中最容易的部分。您可以对gui进行一些验证(例如视图,例如确保电子邮件地址格式正确,文本输入不超过最大值),但业务层也应该验证输入 - 出于我之前提到的原因,当你开始站起来更多的端点,你不必重构。
答案 4 :(得分:1)
这是来自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);
}
您的控制器需要对您的模型的引用。在这种情况下,控制器实际上创建了所有Swing组件。对于C#,您可能希望在此处保留表单初始化,但视图/表单需要引用模型(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
}
View将工作传递给Controller以处理用户的操作(按钮,等等)。 Controller决定在模型中调用/执行的操作。一般来说,模型会做一些事情并改变它的状态(列表中的数字可能更多。无论它做什么)。此时,模型将让其观察者知道它已经改变并自我更新。然后View进入并获取新数据并自行更新。这就是Model和View谈论的原因(你的第3个问题)。
因此模型将具有:
public void notifyObservers()
{
for (Observer o: observers)
{
o.update(); // this will call the View update below since it is an Observer
}
}
所以在View中,你会有这样的东西:
public void update()
{
setListBox(myNums.getNumbers()); // Or whatever form update you want
}
希望有所帮助。我知道它是Java,但这个概念仍然适用。您必须对Observer模式进行一些阅读才能完全获得它。祝你好运!
答案 5 :(得分:1)
财务主任是否应负责任 用于创建MyNumbers?
我会说'绝对不是。'
如果MVC模式被设计为解耦M,V和&amp; C元素,如果C只用new MyNumbers()
实例化M,那么它如何工作?
在Java中,我们会在这里使用类似Spring Framework的内容。您需要一种方法来表达依赖关系 - 或者更确切地说,它是如何实现的 - 在配置文件或其他合适的位置(即不在编译代码中)。
但是这个问题还有另外一个因素:你可能不应该用你打算使用的具体的运行时类型定义myNumbers
变量(在C里面)。使用接口或抽象类,并使其保持打开状态,以确定实际的运行时类型。通过这种方式,将来您可以重新实现IMyNumbers接口以满足新兴要求(您今天不知道的那些),并且您的C组件将继续完美地工作,而不是更明智。
答案 6 :(得分:1)
为什么在下面的MVC图中,View有一个箭头指向模型? Controller不应该始终是View和Model之间的桥梁吗?
它是MVC模型2.您通常可以在Java企业应用程序中看到它 CONTROL执行业务以及处理来自/到MODEL的数据,并选择要呈现给客户端的VIEW。渲染到客户端时,VIEW将使用MODEL:
中的数据alt text http://www.blogjava.net/images/blogjava_net/marco/7342/o_2.JPG
以下是如何从JSP(VIEW)文件中访问数据的示例(bean):
class Person {String name;} // MODEL
My name is ${bean.name} // VIEW
答案 7 :(得分:1)
我会尝试从一个相对不太技术性的立场来回答这个问题。我将尝试通过一个一般的例子。
Controller
控制view
使用的内容。所以,比方说,如果您正在写信给页面,controller
将引导您转到input view
(比如说),而如果您正在阅读同一页面,它将引导您转到success view
(说)。
在向页面写入之后,controller
会将这些参数传递给相关的model
,其中包含与他们必须完成的操作相关的逻辑。如果出现错误,则controller
会引导您转到error view
。
我的知识基于我对Agavi的一个月经验。希望这会有所帮助。
答案 8 :(得分:0)
没有必要将其转换为代码。无论如何,你不会直接纠正它。
答案 9 :(得分:0)
查看
用户界面/负责输入输出/一些验证/需要有办法向外界通知UI级事件
只知道模型
模型
控制器
负责业务逻辑/它创建视图并将各自的模型粘合到它们上/必须能够响应查看事件/访问应用程序的其他层(持久性/外部服务/业务层等)
知道所有事情(至少是视图和模型)并负责将所有内容粘在一起