理解 MVC 模式

发布于 2024-09-11 15:09:18 字数 1437 浏览 4 评论 0原文

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

浊酒尽余欢 2024-09-18 15:09:18

掌握 MVC 的最简单方法是在强制执行它的框架中使用它,话虽这么说。

  • 模型与数据源(DB 或其他)交互,并允许您访问数据。
  • 视图与外界交互,它从某处接收输入并将数据传递给控制器​​,它还监听控制器以确保其显示正确的数据。
  • 控制器是所有魔法发生的地方;控制器操纵数据、推送事件并处理两个方向的更改(往返视图和往返模型)。

这个图非常有帮助(它比维基百科的更有意义):
MVC 图

来源,一篇关于 MVC 的精彩文章!

The easiest way to get a handle on MVC is to use it in a framework that enforces it, that being said..

  • The Model interacts with the datasource (DB or whatever) and gives you access to your data.
  • The View interacts with the outside world, it receives input from somewhere and hands off the data to the Controller it also listens to the Controller to make sure its displaying the correct data.
  • The Controller is where all the magic happens; the Controller manipulates data, pushes events, and handles changes in both directions (to/from the View and to/from the Model).

This diagram is very helpful (it makes much more sense than Wikipedia's):
MVC Diagram

Source, and a great article on MVC!

池木 2024-09-18 15:09:18

至于我的文章中的批评,我想我应该发表一篇关于如何在 PHP 中创建 MVC 模式的文章 在

PHP 中,我将框架分为几个部分,其中一些在涉及 MVC 时是正常的。

主要:

  • 控制器
  • 模型
  • 视图

次要
- ModelLayer

  • ViewLoader
  • Library
  • ErrorLayer

在控制器内,我通常允许所有从主层访问辅助层以及视图和模型。

这是我构建它的方式

|---------|       |------------|       |------------|
| Browser | ----> | Controller | ----> |   Model    |
|---------|       |------------|       |------------|
     |                  |   |                |
     |                  |   |----------------|
     |                  |
     |            |------------|
     -------------|    View    |
                  |------------|

从我的图表中我通常绕过 View <->模型 连接并执行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
    }
}

调用,

class Model_index extends ModelLayer_MySql
{
}

模型也将被放入注册表中,但只允许从ModelLayer或

class Model_index extends ModelLayer_MySqli
{
}

/或文件系统

class Model_file extends ModelLayer_FileSystem
{
}

以便每个类可以特定于存储类型。

这不是传统类型的 MVC 模式,但可以称为采用 MVC。

其他对象(例如视图加载器)不应放入注册表中,因为它们不是专门针对用户兴趣的,而是由其他实体(例如视图)使用的,因为

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());
   }
}

模板文件包含在视图加载器中,而不是包含在视图类中,它将用户方法分开来自系统方法,并且还允许在视图本身内使用方法来实现一般逻辑。

模板文件示例。

<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>

我希望我的例子可以帮助您更多地理解这一点。

As for the criticism within my post I thought I would give a post on how i tend to create an MVC Pattern in PHP

Within PHP i spit the framework up into several sections, of witch some are the normal when it comes to MVC.

Primaries:

  • Controller
  • Model
  • View

Secondariness
- ModelLayer

  • ViewLoader
  • Library
  • ErrorLayer

Within the controller I usually allow all access the secondary layers and the View and Model from Primary.

Here's the way I would structure it

|---------|       |------------|       |------------|
| Browser | ----> | Controller | ----> |   Model    |
|---------|       |------------|       |------------|
     |                  |   |                |
     |                  |   |----------------|
     |                  |
     |            |------------|
     -------------|    View    |
                  |------------|

From my diagram I usually bypass the View <-> Model connection and do a Controller <-> Model and then the link from Controller <-> View assigns the data.

Within my framework I tend to create a object storage system so that i can easily fetch objects and so forth. an example of my object storage is like so

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;
   }
}

Somewhat more advanced by that's the outline, so with this when I first initialize objects i store them like Registry::set("View",new View()); so that there always accessible.

So within my controller witch is the base controller i create several magic methods __get() __set() so that any class that extends the controller I can easily return teh request for example:

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
   }
}

And the user controller

class Controller_index extends Controller
{
    public function index()
    {
       $this->View->assign("key","value"); // Exucutes a method in the View class
    }
}

The model will also be placed into registry but only allowed to be called from ModelLayer

class Model_index extends ModelLayer_MySql
{
}

or

class Model_index extends ModelLayer_MySqli
{
}

or filesystem

class Model_file extends ModelLayer_FileSystem
{
}

so that each class can be specific to the storage type.

This is not the Traditional type of MVC Pattern but it can be called Adoptive MVC.

Other objects such as the View Loader should not be placed into registry as there not specifically for the users interests but used by other entites such as 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());
   }
}

as the template file is being included in the View loader and NOT the View class it separates the user methods from teh system methods and also allows methods to be used within the views themselves for general logic.

Example of template file.

<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>

I hope my examples help you understand that little bit more.

抠脚大汉 2024-09-18 15:09:18

第三个问题的答案

当模型发生变化时,它会通知视图,然后视图使用其 getter 从模型中获取数据。

Answer to the third question:

When the model changes, it notifies the view, then the view gets the data from the model using its getters.

樱花坊 2024-09-18 15:09:18

“根据我的理解,视图是用户看到的。所以它通常是窗口/表单。控制器位于视图和模型之间。控制器将在两个方向上“处理”数据。它还将持久化状态需要时(如果我有一个包含 5 个步骤的向导,则控制器有责任确保它们按正确的顺序制作,等等)。模型是我的应用程序逻辑的核心所在。”

这几乎是正确的。控制器不保留数据。它调用持久数据的服务。原因是,持久数据不仅仅是调用保存。您可能需要对数据进行验证检查,以确保其符合您的业务需求。您可能需要进行一些身份验证以确保用户可以保存数据。如果您在服务中执行此操作,那么您将拥有一组可以反复使用的很好的功能,例如 Web 应用程序和 Web 服务。如果您在控制器中执行此操作(例如对于 Web 应用程序),那么当您编写 Web 服务时,您将必须重构和/或重复代码。

回应您的评论“我不确定我完全理解您的观点。控制器是否检查 UI 输入,或者是模型执行此操作?”

您的控制器应该只控制执行哪些业务功能路径。就是它。控制器应该是代码中最容易编写的部分。您可以在 GUI 上进行一些验证(即视图,例如确保电子邮件地址格式正确,文本输入不超过最大值),但业务层还应该验证输入 - 出于我之前提到的原因,当您开始建立更多端点,您不必重构。

"From what I understood, the View, is what the user sees. So it generally is the window/form. The Controller is inbetween the View and the Model. The Controller will "handle" data in both directions. It will also persist state when needed (if I have a wizard with 5 steps, it is the Controller's responsability to ensure they are made in the correct order, etc). The Model, is where the core of my application logic lives."

This is almost correct. The controller doesn't persist data. It calls a service that persists data. The reason is, persisting data is never just a call to save. You might want to do validation checks on the data to make sure it is sane according to your business needs. You might want to do some authentication to make sure the data can be saved by a user. If you do that in a service, then you have a nice bundle of functionality that you can use over and over again, say for a webapp and a web service. If you do it in a controller, say for a web app, when you go to write your web service you will have to refactor and/or duplicate code.

In response to your comment "I am not sure I totally understood your point. Does the Controller check UI input, or is the Model that does it?"

You controller should only control which business functionality paths get executed. Thats its. Controllers should be the easiest part of the code to write. You can do some validation on the gui (i.e. view, e.g. like making sure email addresses are properly formatted, text inputs dont exceed maximums), but the business layer should also validate the input -- for the reason I mentioned earlier, that when you start standing up more endpoints, you don't have to refactor.

趁微风不噪 2024-09-18 15:09:18

控制者是否应该负责
用于创建 MyNumbers?

我会说“绝对不是”。

如果MVC模式被设计为解耦M、V和& C 元素,如果 C 简单地用 new MyNumbers() 实例化 M,这如何工作?

在 Java 中,我们将使用类似 Spring Framework 的东西。您需要一种方法来在配置文件或其他合适的位置(即不在编译的代码中)表达依赖关系,或者更确切地说是如何实现依赖关系的详细信息。

但这个问题还有另一个因素:您可能不应该使用您打算使用的具体运行时类型来定义 myNumbers 变量(在 C 内部)。使用接口或抽象类,并保留其实际运行时类型的开放性。这样,将来您可以重新实现 IMyNumbers 接口来满足新出现的需求(那些您今天不知道的需求),并且您的 C 组件将继续完美工作,但不会变得更明智。

Should the Controller be responsible
for creating MyNumbers?

I would say 'definitely not.'

If the MVC pattern is designed to decouple the M, V, & C elements, how can this work if the C simply instantiates the M with new MyNumbers()?

In Java, we would use something like the Spring Framework here. You need a way to express the dependency relationship -- or rather the details of how it gets fulfilled -- in a configuration file or other suitable place (i.e. not in compiled code).

But there is another element to this issue: you probably shouldn't define the myNumbers variable (inside C) with the concrete, runtime type you intend to use. Use an interface or an abstract class, and leave it open as to what the actual runtime type is. This way, in the future you can re-implement the IMyNumbers interface to satisfy emerging requirements (those you don't know today) and your C component will continue to work perfectly, none the wiser.

梦幻的味道 2024-09-18 15:09:18

这是来自 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#,您可能希望将表单初始化保留在这里,但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
}

视图将工作传递给控制器​​来处理用户的操作(按钮,等等)。控制器决定在模型中调用/执行什么操作。一般来说,模型会执行某些操作并更改其状态(列表中可能有更多数字。无论它做什么)。此时,模型将让其观察者知道它已发生变化并进行自我更新。然后视图获取新数据并自行更新。这就是模型和视图谈话的原因(你的第三个问题)。

因此模型将具有:

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,但这个概念仍然适用。您必须稍微阅读一下观察者模式才能完全理解它。祝你好运!

This is from Java, but hopefully it will help.

For the main:

public static void main(String[] args) 
{
       MyNumbers myNums = new MyNumbers();  // Create your Model
       // Create controller, send in Model reference.      
       Controller controller = new Controller(myNums); 
}

Your controller needs a reference to your model. In this case, the controller actually creates all the Swing components. For C#, you may want to leave the form initialization here, but the View/Form needs a reference to the Model (myNums) and the Controller (controller). Hopefully some C# people can help on this front. The View also needs to register as an Observer of the Model (see Observer Pattern).

Here is the constructor I have (adjusted for your case):

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
}

The View passes the work to the Controller to handle the user's actions (buttons, whatever). The Controller decides what to call/do in the Model. In general, the Model then does something and changes its state(maybe more numbers in your list. Whatever it does). At the point, the Model will let its Observers know it has changed and to update themselves. Then the View goes and gets the new data and updates itself. That is why the Model and View talk (your 3rd question).

So the Model will have:

public void notifyObservers()
{
    for (Observer o: observers)
    {
        o.update();  // this will call the View update below since it is an Observer
    }
}

So in the View, you'll have something like this:

public void update()
{
    setListBox(myNums.getNumbers());  // Or whatever form update you want
}

Hope that helps. I know it is Java, but the concept still applies. You'll have to do a little reading on the Observer pattern to fully get it. Good luck!

萤火眠眠 2024-09-18 15:09:18

我将尝试从技术性相对较低的角度来回答这个问题,看看它的价值。我将尝试介绍一个一般示例。

Controller 控制使用什么view。因此,比如说,如果您正在写入页面,控制器将引导您进入输入视图(比如说),而如果您正在阅读同一页面,它将引导您进入这是成功视图(比如说)。

写入页面后,控制器会将这些参数传递给相关的模型,其中驻留与必须对它们执行的操作相关的逻辑。如果出现错误,那么控制器会将您引导至错误视图

我的知识是基于我一个月的 Agavi 体验。希望这有帮助。

I will try to answer this from a relatively less technical stand for what it's worth. I'll try walk through a general example.

Controller controls what view is used. So, say, if you are writing to the page the controller will direct you to the input view (say) while if you are reading the same page it will direct you to it's success view (say).

After one writes to the page the controller will pass those parameters to the relevant model where the logic pertaining to what has to be done with them resides. If there is as error then the controller will direct you to the error view.

My knowledge is based on my one month experience with Agavi. Hope this helps.

听不够的曲调 2024-09-18 15:09:18

为什么在下面的 MVC 图中,视图有一个指向模型的箭头?控制器不应该始终是视图和模型之间的桥梁吗?

这就是MVC模型2。在Java企业应用中通常可以看到它
CONTROL 负责处理来自/到 MODEL 的数据,并选择将哪个 VIEW 渲染回客户端。渲染到客户端时,VIEW 将使用来自 MODEL 的数据:

替代文字
(来源:blogjava.net

下面是一个如何从包含 bean (MODEL) 的 JSP(VIEW) 文件访问数据的示例:

class Person {String name;} // MODEL
My name is ${bean.name}     // VIEW

Why does in the following MVC diagram, the View have an arrow to the Model? Shouldn't the Controller be always the bridge between both View and Model?

It is the MVC model 2. You can see it usually in Java enterprise application
where CONTROL does the business as well as processes data from/to MODEL and choose which VIEW to render back to client. When rendering to client, VIEW will use data from MODEL:

alt text
(source: blogjava.net)

Here is an example how to access data from a JSP(VIEW) file which a bean (MODEL):

class Person {String name;} // MODEL
My name is ${bean.name}     // VIEW
放血 2024-09-18 15:09:18
  • 视图绘制模型并将其表示给用户
  • 控制器处理用户输入并将其转换为模型的修改
  • 模型保存数据和修改逻辑

将其转换为代码是没有意义的。无论如何,你不会直接得到正确的结果。

  • View draws the model and represents it to the user
  • Controller handles the user input and translates them to the modifications into the model
  • Model holds the data and modification logic

There's no point translating it into code. You won't get it correct straight out anyway.

从﹋此江山别 2024-09-18 15:09:18

视图

  • 用户界面/负责输入输出/一些验证/需要有一种方法来通知外界UI级别事件

  • 只知道模型

模型

  • 数据结构/表示呈现的数据/不应该包含业务逻辑(也许最多只进行一些数据/结构验证)
  • 只知道他自己(想想只有名字和年龄的 Person 类)

控制器

  • 负责业务逻辑/它创建视图并将相应的模型粘合到它们上/必须能够响应视图事件/访问其他应用程序的各层(持久性/外部服务/业务层等)

  • 知道一切(至少视图和模型)并负责将所有内容粘合在一起

View

  • user interface / responsible with input output / some validation / needs to have a way to notify outside world of UI level events

  • knows only about the model

Model

  • data structure / represents the data that is presented / should not contain business logic (maybe only some data/structure validation at most)
  • knows only about himself (think of a Person class that has only Name and Age)

Controller

  • is responsible for business logic / it crates Views and glues the respective models onto them / has to be able to respond to View events / accesses other layers of the application (persistence / external services / business layers etc.)

  • knows everything (at least View and model) and is responsible of gluing everything together

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文