MVC模型,它们是用来做什么的


MVC Models, what are they for?

是时候让我理解MVC了,所以这就是我想做的;我搞不懂模特该做什么根据维基百科,一个模型:

模型管理应用程序域的行为和数据,响应有关其状态信息的请求(通常来自视图),并响应更改状态的指令(通常来自控制器)。在事件驱动的系统中,模型通知观察者(通常是视图)当信息发生变化时,以便他们能够做出反应。

在CakePHP中,您应该以这种非常简单的方式设置模型:

<?php
class Posts extends AppModel {
    var $name = 'Posts';
}
?>

例如,如果我想要数据库中的最近10篇文章,我将创建一个控制器,它看起来像这样:

<?php
class PostsController {
    function retrieve_latest($number = 10) {
        $posts = $this->Users->find(array(
                'fields' => '*',
                'order' => 'posts.post_id DESC',
                'limit' => $number,
                'page' => '1',
                'conditions' => array('posts.post_display == 1')
        ));
        $this->set('posts', $posts);
    }
}
?>

这个家伙会传递一个叫做posts的变量给我的视图,它会相应地渲染它。问题是,我的模特不应该做点别的吗?,因为如果它像这样简单,就没有自定义模型的意义,我的意思是,它只是模型类的一个空扩展。

这个"模型类的空扩展"已经做了很多事情:它连接到数据库,并完成检索和保存数据的所有微小处理。它应该做更多的事情,包括保持验证规则,在你写数据库的时候强制执行,在前/后过滤器中必要的任何数据传递,以及你在应用程序中需要的任何其他自定义业务逻辑。模型用于存储中心业务数据逻辑,因此任何与表示或输入/输出无关但本质上是对应用程序的核心逻辑建模的东西。仅仅因为基础设置很简单,并不意味着没有更多的东西可以使用。

模型还封装业务逻辑并处理彼此之间的交互。例如,如果Post有Comments,那将在模型中处理。你不会希望控制器先获取Post,然后再获取Comments并组装它们。这样就把了解模型结构的责任推给了控制器,而这本来是不属于它的。

确实,有许多应用程序的模型不包含很多逻辑,如果有的话。只有数据字段而没有业务逻辑的模型可以被认为是DTO(数据传输对象)或仅仅是一个"对象",因为它不"建模"任何类型的业务逻辑。这并不一定是件坏事,这取决于需求。许多应用程序都是简单的表单数据应用程序,不需要任何额外的逻辑。

但是如果你的应用程序有比任何给定表中的数据更多的逻辑,那么逻辑将进入模型。他们不仅对数据建模,还对领域建模。事实上,模型不直接具有相同的数据库结构是很常见的。模型是面向对象的,而数据库通常是关系型的。这两者并不总是以同样的方式解决问题。如果你的模型需要精确地复制你的表,那么你就限制了自己更多的面向对象的能力。

简而言之,任何解释业务行为的东西都要进入模型。控制器只是事件处理程序,响应用户界面请求。控制器通常是为手头的应用程序定制的,而模型应该跨多个应用程序重用,因为它们表示业务逻辑的核心。

以您的示例为例,理想的情况是瘦控制器和胖模型。这意味着你的代码应该按照以下方式重构:

class Post extends AppModel {
    var $name = 'Post';
    function retrieveLatest($limit = 10) {
        return $this->find('all', array(
            'order'=>'Post.id'=>'DESC',
            'limit'=>$limit
        );
    }
}

class PostsController extends AppController {
    function retrieve_latest($limit) {
      $posts = $this->Post->retrieveLatest($limit);
      $this->set(compact('posts'));
    }
}

你的控制器不应该关心获取最新数据所需的复杂细节,这是业务逻辑和模型中接近数据的部分。另一个好处是,您还可以从任何相关模型检索最新的帖子:

$posts = $this->User->Post->retrieveLatest();

你甚至可以更进一步,将retrieveLatest()代码移动到你的AppModel中,这样每个模型都可以继承它:

class AppModel extends Model {
    function retrieveLatest($limit = 10) {
        $model = $this->alias;
        return $this->find('all', array(
            'limit'=>$limit,
            'order'=>array(
                $model . ".id"=>'DESC'
            )
        );
    }    
}

作为一个经验法则,任何时候你发现自己在控制器中构建查询,将它们移动到模型中,并给它们一个描述性的名称。