DDD和MVC:'Model'和'Entity'之间的区别

70
关于MVC中的“Model”概念,我感到非常困惑。现在大多数框架都将Model放置在Controller和数据库之间,Model几乎像是一个数据库抽象层。而“Fat Model Skinny Controller”的概念已经消失了,因为Controller开始执行越来越多的逻辑。
在DDD中,还有一个领域实体的概念,它具有唯一的标识符。据我所知,用户是实体的一个很好的例子(例如唯一的用户ID)。实体有一个生命周期——它的值可以在操作过程中发生变化,然后被保存或丢弃。
上述描述的实体难道不就是MVC中的Model应该扮演的角色吗?我的理解是否正确呢?
为了让事情更加混乱,您还可以引入其他模式,例如存储库模式(可能会放置一个服务)。存储库如何与实体交互是非常清楚的,但是它如何与模型交互呢?
控制器可以有多个模型,这使得模型似乎不是一个“数据库表”,而是一个独特的实体。
更新:在此帖子中,将Model描述为具有知识的东西,并且可以是单个对象或对象集合。因此,实体和模型更或多或少相同。模型是一个全面的术语,而实体更加具体。值对象也可以是一个模型。至少在MVC方面是这样的。可能吗?
因此,在非常粗略的条件下,哪个更好呢?
没有真正的“Model”...
class MyController {
    public function index() {
        $repo = new PostRepository();
        $posts = $repo->findAllByDateRange('within 30 days');
        foreach($posts as $post) {
            echo $post->Author;
        }
    }
}

还有这个,它的DAO使用模型作为基础?

class MyController {
    public function index() {
        $model = new PostModel();
        // maybe this returns a PostRepository?
        $posts = $model->findAllByDateRange('within 30 days');
        while($posts->getNext()) {
            echo $posts->Post->Author;
        }
    }
}

这两个例子甚至没有做我上面描述的事情。我显然迷失了方向。有任何建议?

5个回答

55

实体(Entity)

实体是指业务逻辑处理的单个对象,更具体地说,是带有某种标识符的对象。
因此,许多人将ORM映射的对象称为实体。

有些人将一个代表数据库中单个行的实例的类称为"实体"。

其他一些人更喜欢将这些类中仅包含业务规则、验证和通用行为的那些称为“数据传输对象”,将其他的称为"实体"。

模型(Model)

模型指的是不直接与应用程序UI(=视图)和控制流程(=控制器)相关的东西,而是关于应用程序的数据访问和主要数据抽象方式的工作方式。

基本上,任何符合以上条件的东西都可以成为一个模型。

MVC

你可以在MVC中使用实体作为你的模型。它们代表两个不同的意思,但相同的类都可以叫做这两个名字。

例子

  • Customer类通常非常像一个实体,并且你也可以将其作为应用程序中的数据访问的一部分使用。在这种情况下,它既是实体又是模型。
  • Repository类可能是模型的一部分,但它显然不是一个实体。
  • 如果有一个类被用于业务逻辑层中间,但不对应用程序的其余部分公开,那么它可能是一个实体,但从MVC应用程序的角度来看,它显然不是一个模型。

你的例子

至于你的代码示例,我更喜欢第一个。
模型是一个用于应用程序数据抽象的类,而不是一个名字后缀为“Model”的类。许多人认为后者是膨胀的软件。

即使其名称没有后缀"Model",你也可以将你的Repository类视为你的模型的一部分。

我认为还有一个原因,那就是第一种方法更容易操作。此外,对于之后可能需要理解你的代码的其他人来说,第一种方法更易于理解。


2
模型是一个“层”。例如,“用户模型”这样的东西并不存在。 - Jimbo
@Jimbo 如果模型是一个,我们能否进一步说应用程序模型与其实体之间存在一对多的关系?例如,来自这个答案:"...模型是数据的表示,类(以及通过扩展在应用程序中封装实体的对象)"。 - DavidRR
模型层包含实体和许多其他对象。在Web上下文中,“MVC”不存在于经典形式中,这让我感到困惑,因为他的声誉很高,并来自Nerdery(一个不错的程序员团队,据说如此 :-))。我们在PHP中没有MVC,将其提到讨论的前沿非常重要。 - Jimbo

16

所有答案都是混杂着不同的东西,而且完全是错误的。

在DDD中,模型就像现实世界中的模型: 它是某个东西的简化和抽象。 不多不少。 它与数据、对象或其他任何东西没有关系。 它只是一个领域部分的概念。在每个复杂的领域中, 总会有不止一个模型,例如交易、发票、物流等。

实体不是“具有身份的模型”,而仅仅是具有身份的对象。

仓储不仅仅是第一层缓存,它也是领域的一部分。 它给出了内存对象的错觉,并负责从任何地方获取聚合根(而不是实体!) 并将它们保存下来,即维护对象的生命周期。


9
最后一句话没有必要这么苛刻:我只是在请求澄清。我已经了解了基本情况,但没有找到帮助,所以才会提问。你的回答与 erenon 的本质相同:模型是某个领域中某些东西的表示。模型是对象,但并非所有对象都是模型。一个正方形是一个矩形... - Nathan Loding
6
答案很好,但我赞同Nathan的观点 - 请尽量礼貌,强烈反对使用粗暴的言辞。 - sleske
1
ThinkDDD这个链接需要登录,而且我对它也不是很感兴趣。你的解释和其他人一样正确或错误。你应该提供一些具体的实现来支持你的说法。 - hanzolo
1
在SO上真的没有那种“自以为是”的态度的地方。请保持礼貌。 - Seph
1
@Don Zampano:我同意你关于阅读基础知识的观点。你能给我一个可靠的链接吗?;-) - inf3rno
除了领域驱动设计(DDD)之外,感谢您澄清了许多人胡说八道的事情:模型是一层。您不会有“用户模型”,而是会有一个用户实体。 - Jimbo

8
在您的应用程序中,“model”是保存数据的部分。“实体”在领域驱动设计中是一个具有标识的模型,如果我没记错的话。也就是说,实体是一个通常直接对应于数据库或文件中“物理”元素的模型。我相信DDD定义了两种类型的模型,一种是实体,另一种是值,后者只是没有标识的模型。
仓储模式只是一种索引模型/实体集合的方法。例如,如果您的代码想要订单#13,它将首先询问存储库是否有该订单,如果无法从存储库获取,则会从其他地方获取。这基本上是一级缓存。它在处理模型和实体时没有任何区别,但由于仓储的想法是能够使用它们的ID获取模型,在DDD方面,只允许实体进入仓储。

拿这个话题要谨慎,我也在学习这个模式。但我开始怀疑“模型”一词是否将两个或三个类似但不同的概念混为一谈,特别是在 Laravel 中。1)如何与数据库表交互的抽象。2)表示其中单个记录的响应结构。3)任何代表某种数据集的类都可以称为模型的通用层。因此,要正确回答这个问题,我觉得你首先需要定义你的上下文。 - kmuenkel

2

使用服务和集合的简单解决方案:

<?php
class MyController {
    public function index() {
        $postService = ServiceContainer::get('Post');
        $postCollection = $postService->findAllByDateRange('within 30 days');
        while($postCollection->getNext()) {
            echo $postCollection->current()->getAuthor();
        }
    }
}

编辑: 模型(类)是实体计划的简单表示。模型(对象)是单个实体。服务在模型上操作并向控制器提供具体数据。没有控制器拥有任何模型。这些模型是独立的。
另一方面,映射器将模型映射到持久化层(例如:数据库、第三方后端等)。


好的,只需要在那里放置一个工厂。但是那个模型到底是什么? - Nathan Loding
我认为我的问题是:在这些例子中,“模型”是否是包含“作者”变量的单个“帖子”对象?还是模型是更高级别的东西? - Nathan Loding

2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接