我大部分都同意Dime的回答,即您想为每个业务对象创建模型-业务正在尝试解决的问题应该驱动如何创建模型类。在实践中,我发现为每个表创建一个模型是一个不错的起点。设计正确的架构很可能会模仿您需要在应用程序代码(也称为域模型)中进行建模的业务流程。
使用对象/关系映射层很有用,因此您的域模型包含与数据库模式相同的关系,而无需重复调用数据访问层。以Eloquent for PHP为例。模式和域模型都应设计为支持业务流程。
这导致了Marjan Venema的答案的第一部分:
我说每个表的模型只是在类结构中重新创建数据库。它被称为贫血模型,被认为是反模式。
一个贫血域模型是一个反模式。Venema建议的“每表模型”可以看作是“重新创建数据库”,但是仅说这是一个贫血域模型是绝对不正确的。
从马丁·福勒(Martin Fowler):
贫血域模型的基本症状是,乍一看它看起来像真实的东西。在领域空间中有许多以名词命名的对象,这些对象与真实领域模型所具有的丰富关系和结构相关联。当您查看行为时就会发现问题所在,并且您意识到这些对象几乎没有任何行为,这使它们仅比一堆吸气剂和吸气剂小得多。
(重点,我的)
贫血症域模型中的关键因素是域模型类上缺少行为或方法。
这是因为类旨在同时具有数据和行为。如果将模型限制为一个表,则将需要处理来自多个表的数据和行为的代码(行为)放在哪里?
同样,您可以并且应该将行为放入域模型中,即使它们仅映射到一个表也是如此。影响多个表的行为实际上会影响碰巧映射到多个表的多个对象。域驱动设计是一种解决与Venema完全相同的问题的方法:“您将需要处理来自多个表的数据和行为的代码(行为)放在哪里?”
答案是汇总根。马丁·福勒指出:
聚合是域驱动设计中的一种模式。DDD聚合是域对象的群集,可以将它们视为一个单元。一个示例可能是订单及其订单项,它们将是单独的对象,但是将订单(连同其订单项)视为一个单独的汇总很有用。
(重点,我的)
“域对象集群”也可以视为“映射到多个表的域模型”。应该在聚合根上定义影响多个表的行为-封装影响多个表或对象的“事物”的类:
同样,从马丁·福勒(Martin Fowler):
聚合通常会包含多个集合以及简单的字段。
要回答OP的原始问题:
...是否将每个数据库表创建一个模型视为好习惯?这样,方法不会被编写两次。
我想说这是一个不错的起点,但是请注意,您的架构和对象模型不必匹配100%。对象模型应该更关注于实现和执行业务规则。该模式应更集中于以模块化和可伸缩的方式存储业务数据。
每个控制器的模型都不是一个好习惯,尽管存在称为Controller Model的模型变体,但确实适合Controller层。一个视图模型是域模型的改组,以适应某一种展示,无论是网页或形式的GUI应用程序。