在MVC设计中构建正确的模型

Dav*_*ave 6 php oop model-view-controller design-patterns

我在这里贴了一个幽灵,这让我感到沮丧多年.这是一个关于如何构建正确的模型,正确的对象的问题.

让我解释.假设我有一篇文章.文章有标题,评级,正文和评论.

Comment类包含作者,时间戳,文本.

文章可以有0个或更多评论.到现在为止还挺好.这个概念没问题.但...

  • 在展示文章时,我会展示一切.文章属性,包括其评论.
  • 在显示文章列表时,我只显示文章名称和一些正文副本.

这是我感到困惑的地方,因为我不需要加载评论信息,当我有大量文章和大量评论时,这会产生显着的性能差异.

我应该建两个型号吗?一个用于Article,一个用于ArticlesInList?我应该将评论的负载委托给延迟模式(这是可能的),只在必要时检索它们吗?

面对和解决这个问题的正确方法是什么?

谢谢.

tim*_*dev 4

尝试对业务对象进行建模时需要做出很多权衡。

根据您的示例,我可以想到一些方法,主要围绕延迟加载注释。如果我相当确定事情不会变得更复杂,我会这样做:

首先,为文章和评论创建实体,它们仅表示数据库中每个表中的数据。编写 setter 和 getter。在 Article 上实现 loadComments() 方法。

实现一个或多个 Collection 类,例如 ArticleCollection。您可能有一个服务类来获取符合某些条件的文章。ArticleService::fetchArticles() 将返回没有加载评论的文章。然后实现 ArticleCollection 的 loadComments() 方法,该方法加载集合中所有文章的所有评论。起初,这只能迭代调用 loadComments 的文章——但您可以稍后用单个查询实现替换它。

这是文章和文章集合的开头。如果您实现 CommentCollection 类,您可以在 Article 内使用它来保存评论等。

<?php
/**
 * Extends a base model class that provides database-related methods -- not ideal, 
 * but trying to stay focused here.
 */
class Article extends Model {
    private $_data;
    private $_fields = array('id','title','body','author');

    /** 
     * Constructor can take an array of values to initialize.
     */
    public function __construct($data=null){
        if (is_array($data)){
            foreach($this->_fields as $field){
                $this->_data[$field] = $data[$field];
            } 
        } 
    }

    public function getId(){ return $this->_data['id']; }
    // more getters, and setters, here.

    public function loadComments(){
        $result = $this->query('SELECT * FROM Comment WHERE article_id = ' . $this->getId());
        $this->_comments = array();

        foreach($result as $c){
            //instantiate a new comment (imagine Comment's constructor is very similar to Article's
            $this->_comments[] = new Comment($c);
        } 
    }
}

class ArticleCollection extends Model {
    /**
     * An array of Articles, indexed by article_id
     */
    private $_articles = array();

    /**
     * Naive implementation.  A better one would grab all article IDs from $this->_articles, and
     * do a single query for comments WHERE article_id IN ($ids), then attach them to the 
     * right articles.
     */
    public function loadComments(){
        foreach($this->_articles as $a){
            $a->loadComments();
        }
    }

    /**
     * Add article to collection
     */
     public function addArticle(Article $article){
         if (empty($article->id)) throw new \Exception('Can\'t add non-persisted articles to articlecollection!');
         $this->_articles[$article->id] = $article;
     }
}
Run Code Online (Sandbox Code Playgroud)

上面的内容非常基本——例如,您可以应用其他设计模式来分解数据库访问,这样它就不会那么紧密耦合。但我只是想描述一种以理智的方式延迟加载评论的策略。

最后的一些建议:不要陷入许多框架所做的陷阱,并认为数据库中的表和模型之间存在某种神圣的相关性。模型只是对象。它们可以做不同种类的事情(代表评论或用户等简单事物),或者代表对这些简单事物进行操作的服务之类的事物,或者它们可以是这些个体事物的组(集合)之类的事物。

一项有趣的练习是编写类,并用虚拟数据填充它们。尽最大努力完全忘记将涉及数据库。制作支持您所需用例的对象。然后,完成后,弄清楚如何将数据保存到数据库或从数据库加载数据。