胖模型和瘦控制器听起来像是在创造上帝模型
Posted
技术标签:
【中文标题】胖模型和瘦控制器听起来像是在创造上帝模型【英文标题】:Fat models and skinny controllers sounds like creating God models 【发布时间】:2012-12-12 06:04:41 【问题描述】:我已经阅读了很多提倡胖模型和瘦控制器方法的博客,尤其是。 Rails 营地。结果,路由器基本上只是弄清楚在什么控制器上调用什么方法,而所有控制器方法所做的就是调用模型上的相应方法,然后调出视图。所以我在这里有两个我不明白的问题:
-
控制器和路由器实际上并没有太多不同的任务,只是在基于路由的上帝模型上调用一个方法。
模型做的太多了。发送电子邮件、创建关系、删除和修改其他模型、排队任务等。基本上,现在您拥有神一样的对象,这些对象应该完成所有可能与建模和处理数据有关的事情。
你在哪里画线?这不就是落入神模式了吗?
【问题讨论】:
【参考方案1】:我认为您可以区分单个胖模型(可能命名为 App 或应用程序)和几个分解为逻辑组(业务、客户、订单、消息)的胖模型。后者是我构建应用程序的方式,每个模型大致对应关系数据库中的数据库表或文档数据库中的集合。这些模型处理创建、更新和操作构成模型的数据的所有方面,无论是与数据库通信还是调用 API。控制器非常负责调用适当的模型和选择模板。
【讨论】:
【参考方案2】:如果“模型”类的实现很差,是的,您的担忧是相关的。 模型类不应该做电子邮件(基础设施任务)。
真正的问题是 MVC 中的模型意味着什么。 它不限于具有几种方法的 POCO 类。 MVC 中的模型意味着数据和业务逻辑。将其视为经典核心 POCO 模型的超集。
视图 ==== 控制器 ==== 模型 ---> 业务流程层 --> 核心模型
加入基础设施程序集和数据访问层并使用注入将其交给 BPL,然后您的流程就可以按预期使用 MVC。
BPL 可以调用 UoW / Respository 模式,并通过注入的对象或接口模式执行业务规则和调用基础设施功能。
所以建议保持控制器瘦身并不意味着经典Core模型中的“person”类应该有50个方法,并且直接调用Email。你认为这是错误的,这是对的。
如果直接调用,控制器可能仍需要实例化基础设施类并将其注入 BPL 或核心层。应该有一个业务层或至少有一个类来编排跨经典对象模型类的调用。 好吧,这就是我的“观点”;-)
对于 MVC 的一般看法,请参阅 wiki 描述 http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller
一个关于 MVC 中“M”的小博客。 http://www.thedeveloperday.com/skinny-controllers/
【讨论】:
如果你不同意,至少要礼貌地证明你的观点是正确的【参考方案3】:将 Rails 视为 MVC 设计模式的主要部分可能不是最好的主意。所述框架存在一些固有的缺陷(我在different post 中对此进行了详细阐述),而社区直到现在才开始解决后果。您可以将 DataMapper2 development 视为第一步。
一些理论
给出这种建议的人似乎受到了一种非常普遍的误解的困扰。所以让我首先澄清一下:模型,在现代 MVC 设计模式中,不是一个类或对象。模型是一个层。
MVC 模式背后的核心思想是Separation of Concerns,其中的第一步是表示层和模型层之间的划分。就像表示层分解为控制器(实例,负责处理用户输入)、视图(实例,负责 UI 逻辑)和模板/布局一样,模型层也是如此。
模型层组成的主要部分有:
Domain Objects
也称为域实体、业务对象或模型对象(我不喜欢后一个名称,因为它只会增加混淆)。这些结构就是人们通常错误地称为“模型”的东西。他们负责包含业务规则(特定领域逻辑单元的所有数学和验证)。
存储抽象:
通常使用data mapper 模式实现(不要与滥用此名称的ORMs 混淆)。这些实例的任务通常是从域对象中存储和检索信息。每个域对象可以有多个映射器,就像有多种存储形式(DB、缓存、会话、cookie、/dev/null)一样。
服务:
负责应用程序逻辑的结构(即域对象之间的交互以及域对象与存储抽象之间的交互)。它们应该充当表示层与模型层交互的“接口”。这通常是在类 Rails 代码中最终在控制器中的内容。
在这些组之间的空间中还可能存在几种结构:DAOs、units of work 和 repositories。
哦……当我们(在网络环境中)谈论与 MVC 应用程序交互的用户时,它不是人类。 “用户”实际上是您的网络浏览器。
那么神灵呢?
控制器应该与服务交互,而不是使用一些可怕的单体模型。您将数据从用户输入传递到特定服务(例如 MailService
或 RecognitionService
)。控制器通过这种方式更改模型层的状态,但它是通过使用清晰的 API 来完成的,并且不会弄乱内部结构(这会导致抽象泄漏)。
此类更改可能会立即引起一些反应,或仅影响视图实例从模型层请求的数据,或两者兼而有之。
每个服务都可以与任意数量(尽管通常只有少数)域对象和存储抽象进行交互。例如,RecogitionService
不会关心文章的存储抽象。
结束语
通过这种方式,您可以获得可以在任何级别进行单元测试、耦合度低(如果实现正确)并且具有清晰易懂的架构的应用程序。
不过,请记住:MVC 不适用于小型应用程序。如果您正在使用 MVC 模式编写留言簿页面,那么您做错了。此模式旨在在大规模应用程序中执行法律和秩序。
对于使用 php 作为主要语言的人,this post 可能是相关的。用一些sn-ps的代码对模型层的描述有点长。
【讨论】:
非常有用且完整的答案!你知道任何解释 MVC 架构模式的书吗?特别是模型部分,大家误以为“模型代表数据,其他什么都不做”。这听起来更像是域对象的想法,而不是“模型”-> tomdalling.com/blog/software-design/… @thermz, afaik,确实没有专门处理 MVC 模式的书籍。我通常只是告诉人们阅读PoEAA,然后去挖掘。也许这个list of links 可能有用。我发现,当人们对 OOP 原则和概念有了扎实的掌握后,这种模式就变得很容易理解了。 @tereško 漂亮的答案。 Hibernate 能做到这一点吗?我不相信这里的答案-> ***.com/questions/1308096/… @Ankan-Zerob 您可能注意到了,我不是 Java 开发人员,但根据我对 Hibernate 的了解,它为持久层提供了完整的工具集。它将为您提供其中描述的部分内容,但不是完整的模型层。 @johnny 据我所知。 php 的大多数所谓的“mvc 框架”都是 Rails 的变体。而且,作为课程的一部分,它们中的大多数都带有一些基于 active record 的 ORM 解决方案(众所周知,这些东西对数据库更改很脆弱)。您可以使用 SF2.x 或 ZF2.x 实现类似的功能,但框架的重点不是实现/强制执行特定架构,而是提供工具。此外,对于 MVC,它是由应用程序代码而不是框架实现的。以上是关于胖模型和瘦控制器听起来像是在创造上帝模型的主要内容,如果未能解决你的问题,请参考以下文章