每个数据库表的模型?


11

我正在使用codeigniter,并且发现自己处于类似的情况,在其中我重复了Model方法。我正在为每个控制器创建一个模型。但是我会为每个数据库表创建一个模型是一种好习惯吗?这样,方法不会被编写两次。

而不是每个控制器的模型或共享的几个小模型。

例如,如果我有一个模型方法get_user($ user_id),我可以在users_models.php上写它。

我看到的缺点之一是,我可能不得不调用多个模型,而不仅仅是controllername_models.php。

加载可能无法使用控制器几种方法的多个模型会影响性能和速度吗?解决这个问题的最佳方法是什么?

注意:也有类似的问题,但是它们没有涵盖每个数据库表的Model基础。

Answers:


8

我说每个表的模型只是在类结构中重新创建数据库。它被称为贫血模型,被认为是反模式。这是因为类旨在同时具有数据和行为。如果将模型限制为一个表,则将需要处理来自多个表的数据和行为的代码(行为)放在哪里?然后,您的控制器将需要使用一个或多个这些“表”模型的模型...因此,除了最基本的应用程序之外,这种方法几乎不会带来任何好处。


只是一个附录-它被马丁·福勒(Martin Fowler)视为反模式。在这里句号。他对这种情况有一些见识,但这并不意味着它很糟糕 -与God Object不同,它几乎总是不好的,这样的结构有时非常有用且易于维护。我根本不认为这是反模式。
T. Sar

1
例如,“贫血模型”符合SOLID标准-具有单一用途的对象(存储数据)真的不好吗?尽管我确实尊重福勒先生所说的许多话,但那是胡说八道。
T. Sar

7

通常,您不应按表或控制器创建模型,而应按业务对象创建模型。有时它与表结构或控制器之间可能是1:1的关系,但不是必需的。

在您的示例中,您可能有一个users_model由多个控制器调用的类。这很好,有时甚至是理想的。但是,在大多数情况下,users_model该类将从多个表中获取其数据。
例如,可以(不是必须)从与主表具有一对多关系的单独表中获取类的last_login_date属性。users_modeluser_auditusers

我要说的是,如果每个业务对象只有一个SQL表,则很可能数据库结构未规范化。


3

我大部分都同意Dime的回答,即您想为每个业务对象创建模型-业务正在尝试解决的问题应该驱动如何创建模型类。在实践中,我发现为每个表创建一个模型是一个不错的起点。设计正确的架构很可能会模仿您需要在应用程序代码(也称为域模型)中进行建模的业务流程。

使用对象/关系映射层很有用,因此您的域模型包含与数据库模式相同的关系,而无需重复调用数据访问层。以Eloquent for PHP为例。模式和域模型都应设计为支持业务流程。

这导致了Marjan Venema的答案的第一部分:

我说每个表的模型只是在类结构中重新创建数据库。它被称为贫血模型,被认为是反模式。

一个贫血域模型是一个反模式。Venema建议的“每表模型”可以看作是“重新创建数据库”,但是仅说这是一个贫血域模型是绝对不正确的。

从马丁·福勒(Martin Fowler):

贫血域模型的基本症状是,乍一看它看起来像真实的东西。在领域空间中有许多以名词命名的对象,这些对象与真实领域模型所具有的丰富关系和结构相关联。当您查看行为时就会发现问题所在,并且您意识到这些对象几乎没有任何行为,这使它们仅比一堆吸气剂和吸气剂小得多。

(重点,我的)

贫血症域模型中的关键因素是域模型类上缺少行为或方法。

这是因为类旨在同时具有数据和行为。如果将模型限制为一个表,则将需要处理来自多个表的数据和行为的代码(行为)放在哪里?

同样,您可以并且应该将行为放入域模型中,即使它们仅映射到一个表也是如此。影响多个表的行为实际上会影响碰巧映射到多个表的多个对象。域驱动设计是一种解决与Venema完全相同的问题的方法:“您将需要处理来自多个表的数据和行为的代码(行为)放在哪里?”

答案是汇总根。马丁·福勒指出:

聚合是域驱动设计中的一种模式。DDD聚合是域对象群集,可以将它们视为一个单元。一个示例可能是订单及其订单项,它们将是单独的对象,但是将订单(连同其订单项)视为一个单独的汇总很有用。

(重点,我的)

“域对象集群”也可以视为“映射到多个表的域模型”。应该在聚合根上定义影响多个表的行为-封装影响多个表或对象的“事物”的类:

同样,从马丁·福勒(Martin Fowler):

聚合通常会包含多个集合以及简单的字段。

要回答OP的原始问题:

...是否将每个数据库表创建一个模型视为好习惯?这样,方法不会被编写两次。

我想说这是一个不错的起点,但是请注意,您的架构和对象模型不必匹配100%。对象模型应该更关注于实现和执行业务规则。该模式应更集中于以模块化和可伸缩的方式存储业务数据。

每个控制器的模型都不是一个好习惯,尽管存在称为Controller Model的模型变体,但确实适合Controller层。一个视图模型是域模型的改组,以适应某一种展示,无论是网页或形式的GUI应用程序。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.