2

好的,我现在了解 MVC 概念的基础知识,我知道有人问过类似的问题,但仍然没有找到明确的答案。阅读 MVC 时我发现了一些相互矛盾的例子,所以我想找出哪个概念更好。

我应该使用我的控制器从模型中加载数据,然后将该数据传递给视图,还是应该让视图从模型中加载数据并使用控制器来选择适当的视图。

对我来说更自然(正确)的方式是控制器应该加载模型,但如果我需要具有 2 个不同视图的相同内容,例如:

  1. 视图显示简单的文章文本
  2. 视图显示相同的文章文本,但也显示带有文章作者信息的框。

让我感到困惑的是我有一个请求,给我看 ID 为 33 的文章。在第一种情况下,一切都很清楚,但现在我的第二个视图使用显示附加数据(关于作者)的不同模板进行渲染,所以我应该让查看从模型(关于作者)请求数据还是整个逻辑应该由控制器完成?

这很令人困惑,因为现在控制器应该根据视图应该呈现的模板从模型中请求适当的数据。

希望我有道理:)

4

2 回答 2

2

简短回答:将模型传递给控制器​​和视图。

长答案:在 MVC 中,控制器不会“从模型加载数据然后将该数据传递给视图”。视图与模型有直接关系,并从中请求数据。请参阅:MVC 应该如何在 CodeIgniterhttp://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller中工作:“视图从模型请求它需要的信息生成输出表示。”

因此,要启用松散耦合,请完全独立地启动模型视图和控制器,并将它们相互传递。

这允许严格分离 MVC 提倡的关注点,并允许您将任何组件与任何其他组件重用,因为没有任何东西是硬编码的。

就像是:

$model = new Model;
$controller = new Controller($model);
$view = new View($model, $controller);
echo $view->output();

控制器不应选择视图,也不应选择模型。通过将此责任放在控制器中,控制器不能与其他视图或模型重用。

编辑:我已更新此内容以回答 tresko 关于视图为何需要了解其控制器的评论。

视图需要控制器以避免将控制器硬编码到视图中。这是为了让视图知道它在当前上下文中与哪个控制器配对并可以回发给它。

事件(用户操作)在视图中触发,需要由控制器处理。

有3种方法:

1)硬编码视图:控制器关系,在网络上这是通过使用来实现的<a href="/some/hardcoded/route";或<a href="' . $this->router->create('someController, 'action') . '>'这消除了将视图与任何其他不希望的控制器一起使用的可能性。

2)将控制器传递给视图并让视图知道其事件将被触发到哪个控制器。在网络上,使用这种方法,视图还需要一个路由器,它将控制器操作转换为路由。例如<a href="' . $this->router->getRoute($this->controller, 'action') . '>'

3)将视图传递给控制器​​并让控制器在视图上设置操作:(控制器代码)$this->view->setEvent('buttonClick', $this->router->getRoute($this, 'action'))...(视图代码)<a href="' . $this->getEvent('buttonClick') . '>'

这些,

1) 是最不可取的,因为它严重影响了灵活性。视图只能在非常特定的控制器上调用操作。

2) 对开发人员来说是最少的工作量,但每个控制器都需要一个特定的接口。

3)这提供了最大的技术灵活性,但开发人员需要做更多的工作,并且控制器需要了解很多关于其视图的信息,除了 API 之外,它还必须知道视图中可用的事件。如果一个视图被更新并且有一个新的动作,每个控制器都需要被更新来解释它。这也适用于 2),但是因为 2 可以使用接口轻松处理,所以跟踪使用它的每个类要容易得多。

在我看来,2 和 3 都是很好的方法,但 2 更好,因为它允许更健壮的系统并允许最多的重用,缺点是控制器必须实现特定的接口。3 允许控制器有任何接口,但它必须知道很多关于它的视图。

CakePHP 和其他流行的框架在他们的示例中倾向于对关系进行硬编码(例如http://book.cakephp.org/2.0/en/views.html),echo $this->Html->link('edit', array( 'action' => 'edit', $post['Post']['id'])); ?>链接只能转到“编辑”控制器。这严重影响了重用。

于 2013-02-04T17:15:18.560 回答
-1

我的建议是,将数据源与视图结合起来的逻辑应该完全发生在控制器中。视图不应绑定到特定的数据源。

例如,如果您有一个使用 Smarty 语法(或类似语法)和命名占位符的视图,那么您可以使用任何数据源、文本、模型等来提供信息以呈现到模板中。如果视图与模型相关联,您需要修改模型和视图,同时了解对另一个的影响。

与松散耦合相比,像这样的紧密耦合会因意外忽略某些东西而导致更多问题,松耦合使您意外破坏某些东西的机会更少。

例子:

class Page_Controller extends Controller {

  // __construct/__destruct/__callStatic/__call/etc, whatever you need in your implementation

  // -------------------------------------------------------
  // Adjust to suit your situation for passing data
  // This controller doesn't care where objSource comes from
  // -------------------------------------------------------
  private function pageSpecificImplementation($objSource = null){

    // using a factory class - but assume a view is created in whatever way works for you
    // the key thing here is that the view could be anything that can be returned as a string - but use whatever works for you
    $tplMain = make::view( 'template-url-or-path' )->assign(array(
       'placeholder1' => $objSource->value1,
       'placeholder2' => $objSource->value2
    ));

    $tplSub = make::view( 'template-url-or-path' )->assign( $objSource );

    $tplMain->assign('sub',$tplSub->render())->render();

    // $tpl is some form of html? csv?, who knows - not relevant at THIS stage

    // okay - now I know what I want to do!
    // decide what to do with it here - output headers for html
    // save to a file
    // output and cache the output, whatever works for you here
    // output to pdf?
    // send as an email?
    output::html( $tplMain, $cacheable, $cachetime... );
    // output::email( $tplMain, $extra_params );
    // output::pdf( $tplMain, $extra_params );
  }

}

在这里,您使用的是视图,而没有将其与输出紧密耦合。您的控制器可以在运行时根据正在运行的任何业务规则修改输出,但数据源不绑定到视图,输出也不绑定到视图。

我建议以遵循类似原则的方式分离的“一些”实现。YMMV 取决于您正在做什么以及您希望如何实现它,但请尝试在 MVC 中保持每个元素分开。

在某些实现中,您会看到在视图中“替换”事物的逻辑,而无需提及“什么”视图。这通常在 Smarty 中完成。然后可以由控制器的流程确定视图。可以从多个模型或其他来源中提取数据,这可能会或可能不会影响哪个视图是合适的。

因此,您绝对应该将数据加载与视图分开。将它保存在控制器中,这是应该做出决定的地方。除非您考虑到特定的用例,否则视图不应与模型连接,例如具有紧密耦合主题视图的主题模型,其中不涉及额外的业务逻辑(不太可能但可能?)。

于 2013-02-04T17:03:33.763 回答