【问题标题】:What is the usage of Model in MVC? Is it actually useful?MVC中Model的用途是什么?它真的有用吗?
【发布时间】:2011-07-02 21:46:36
【问题描述】:

我是新手,请耐心等待。我最近在几个项目中使用了一个 MVC 框架,一段时间后,我对 MVC 中“模型”的感知有用性感到失望。

我了解了控制器和视图的用处,我知道表示和逻辑之间的分离对于使代码在未来更易于维护很重要,尽管不一定更快或更健壮。

如果所有逻辑首先都应该放在控制器中,我看不到 Model 有任何用处,尤其是 Active-Record。我们已经有了一种强大且易于使用的语言来与数据库进行通信,对吗?它被称为 SQL。对我来说,当模型像活动记录一样实现时,它的有用性取决于您是否希望您的应用适合多个数据库。

所以我要问的是,如果您只使用一个数据库,为什么还要使用 Models 和 Active-Records?为什么不只使用 SQL?为什么要增加额外的复杂性?你们有任何案例研究/现实生活中的故事,模型实际上可以比仅使用数据库类和 SQL-away 做得更好吗?

再次,对不起,如果我看起来如此无知,但我真的不知道为什么模型很重要。感谢您的回答。

【问题讨论】:

    标签: model-view-controller architecture paradigms


    【解决方案1】:

    首先,您假设模型层必须使用某种 ORM,以便抽象出 SQL。这不是真的:您可以创建一个模型层,它与控制器层松散耦合,但与特定 DBMS 紧密耦合,因此避免使用功能齐全的 ORM。

    有一些 ORM 库,例如 Hibernate (Java)、NHibernate (.NET)、Doctrine (PHP) 或 ActiveRecord-Rails (Ruby),它们确实可以为您生成所有实际的 SQL 语句;但是如果你认为 ORM 是不必要的,并且你想手动定义所有的 SQL 语句,就不要使用它们。

    不过,恕我直言,这确实意味着您应该将所有与数据库相关的逻辑都放在控制器层中。这被称为“胖控制器”方法,它多次导致臃肿、无法维护的代码。您可以将它用于简单的 CRUD 项目,但除此之外的任何事情都需要存在真正的“模型”。

    您似乎关心 MVC。请阅读有关 TDD 的内容。一位智者曾经说过“legacy code is code without tests”。当您了解到自动化单元测试“真实”代码一样重要时,您就会明白为什么企业应用程序中有这么多层,以及为什么您的模型层应该与控制器分开。试图做所有事情(表示、业务逻辑、数据持久性)的代码块根本无法轻松测试(也无法顺便调试)。

    编辑

    “模型”是一个有点模糊的术语。根据您从哪里看,它可能意味着略有不同。例如,PHP e Ruby 程序员经常将其用作Active Record 的同义词,这是不准确的。其他一些开发人员似乎认为“模型”只是某种DTO,这也是不对的。

    我宁愿使用Wikipedia中看到的模型定义:

    MVC 的中心组件,模型,根据问题域捕获应用程序的行为,独立于用户界面。模型直接管理应用程序的数据、逻辑和规则。

    因此,模型是大多数 MVC 应用程序中最大、最重要的层。这就是为什么它通常分为子层:域、服务、数据访问等。模型通常通过域公开,因为在那里您可以找到控制器将调用的方法。但是数据访问层也属于“模型”。任何与数据持久性业务逻辑相关的东西都属于它。

    【讨论】:

    • 感谢您的回答!我想我现在明白了。你提到了一个'..要求存在一个业务层'——这个业务层,是模型吗?
    • 感谢您启发我 - 阅读有关 TDD 的信息 - 看起来很棒。会和我的朋友讨论。从今天开始,我的编程习惯将会改变:)
    【解决方案2】:

    这根本不是一个无知的问题!只是你问它而不是简单地忽略整个 MVC 理论并随心所欲地做这个事实很好。 :-)

    回答您的问题:从概念上讲,模型只是为您的数据提供了一个很好的抽象。模型可以让您思考“我的应用程序的对象如何相互关联,它们如何交互以及我如何从他们那里获取我需要的数据”。

    与视图和控制器帮助您将表示与逻辑分开的方式相同,模型可帮助您将应用程序的逻辑(无论如何从用户的角度)与关于数据实际来自何处以及如何在内部表示的具体细节分开.

    举一个更具体的例子(如果不完全现实的话):理论上,您可以通过 SQL 查询获取所有数据的方式编写整个应用程序。但后来你意识到你想使用一些 noSQL(CouchDB 等)引擎,因为你需要水平扩展。

    使用模型(当然还有一个可以使用这两种存储类型的框架 :-))您不必担心细节,因为您的所有重要数据已经通过模型以通用方式表示,并且视图和控制器都可以对该表示进行操作。

    如果没有它们,您可能必须重写大量代码才能使您的数据获取适应新的后端。

    这只是无聊的存储部分。使用纯 SQL,定义应用程序对象(即业务逻辑)之间的交互要困难得多,因为您不会在 SQL 中这样做(可能无论如何)。

    这不是一个完美的解释(远非如此),但我希望它有所帮助。

    【讨论】:

    • 感谢您的回答!可以肯定地说,如果我们的应用程序不需要使用另一个数据库(如果我们不希望更改数据库或使用多个数据库) - 模型的有用性会降低吗?如果我理解正确,那么使用 Model 将是程序员所做的一种风险缓解措施,“以防万一客户要求我们更改后端”。
    • 在这种情况下,它只是略微减少。模型的好处,特别是能够抽象出实现细节并专注于实际逻辑的好处通常远远超过其他所有。如果您只是开始到处转储 SQL,您可能最终会编写更多人为的代码,因为您必须将所有这些数据映射到您的控制器和视图可以轻松使用的地方。根据我的经验,你最终会觉得需要做一些本质上是对象模型的事情,即使你一开始并没有意识到这一点。无论如何,你也可以这样做。 :-)
    【解决方案3】:

    在大多数现实生活中,来自用户的数据不会直接进入数据库。

    它必须经常被验证、过滤或转换。

    模型层的作用通常是通过执行这些操作来确保数据正确到达后端存储(通常是数据库),这不应该是控制器(瘦控制器,胖模型)的职责,并且不是数据库引擎本身的责任。

    换句话说,模型层负责 - 或“知道” - 如何处理数据。

    大多数现代 MVC 框架都提供了在数据有效性要求上指定合同的方法,例如 Rails。

    这是来自http://biodegradablegeek.com/2008/02/introduction-to-validations-validation-error-handling-in-rails/的示例:

    class Cat
      validates_inclusion_of :sex, :in => %w(M F), :message => 'must be M or F'
      validates_inclusion_of :vaccinated, :in => [true,false]
      validates_inclusion_of :fiv, :in => [true,false]
      validates_inclusion_of :age, :within => 1..30
      validates_each :weight do |record, attr, value|
          record.errors.add attr, 'should be a minimum of 1 pound' if value and value  /^[01][0-9]\/[0-9]{2}\/[0-9]{4}$/
      validates_length_of :comment, :allow_blank => true, :allow_nil => true, :maximum => 500
    end
    

    这里,有几个数据有效性要求不能由数据库处理,也不应该在控制器中处理,因为对这些要求的任何修改都可能在几个地方破坏代码。

    因此,模型是确保数据与您的领域一致的最佳场所。

    关于它还有很多话要说,但我想解决一个对我来说似乎很重要的问题,受实践经验的启发:)

    【讨论】:

    • 感谢您的回答!我总是将数据验证放在我的控制器中,这是一种不好的做法吗?在我的框架中,验证器类与模型类是分开的——验证器类本身被编写为专门用于控制器内部。那么我使用的框架的模型实现是假的吗?
    • 您是说验证/数据需求应该由模型来处理,但实际上,许多应用程序的数据需求实际上是基于业务规则的(例如,不允许该会员购买更多一年多于 2 台 iPad)。如果我理解正确,使用您的示例,此业务规则将写入模型而不是控制器,这是一个好的 MVC 实践吗?
    • 没错,正如有人在另一个答案中所说,业务逻辑应该属于Model层。话又说回来,这些层之间的边界非常模糊,一些实现更喜欢不遵循瘦控制器/胖模型范式。
    • 谢谢!根据这个答案和@rsenna 的答案,我现在理解它的方式是,使用模型创建一个集中的路径来更新/插入/删除您的数据,因此 1)使单元测试更容易 2)重用验证,不仅数据类型约束,还有业务规则 3) 由于它是集中式的,因此业务规则中的任何更改都将更容易应用 - 这是正确的吗?
    【解决方案4】:

    模型应该包含您的所有逻辑。控制器只负责与用户交互相关的逻辑。所有与域相关的功能(所谓的“业务逻辑”)都应该放在模型中并与控制器代码分离。像这样,您可以更好地分离关注点和代码可重用性。

    例如,假设您正在编写一个应用程序,让用户输入有关他们自己的信息并接收饮食建议。

    一方面,您可以将与转换用户提供的数据相关的代码放入模型部分的饮食建议列表中。这包括数据库访问,还包括与所讨论的问题(问题域)相关的任何计算、算法和处理。

    另一方面,您将用于登录用户、显示表单、收集表单数据、验证数据的代码放在控制器中。例如,通过这种方式,您可以稍后将 api 添加到您的应用程序(它使用不同的代码进行身份验证、从用户获取数据、验证等)并重用代码来生成结果(来自模型)。

    这只是该模型的优点的一个示例。

    【讨论】:

      【解决方案5】:

      我总是将模型与数据相关联,无论它在哪里或如何表示。在 MVC 中,V 显示数据,C 处理更改。即使您在控制器内的 HashMap 中将所有数据显示在屏幕上;该 HashMap 将被称为模型。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-30
        • 2010-09-27
        • 2011-12-17
        • 2010-11-21
        • 1970-01-01
        • 2015-02-23
        相关资源
        最近更新 更多