我是新手,所以请耐心等待。我最近在几个项目中使用过一个MVC框架,过了一段时间,我对MVC中“模型”的有用性感到失望。
我得到了控制器和视图的有用性,我知道表示和逻辑之间的分离对于使代码在未来更易于维护非常重要,尽管不一定更快或更强大。
如果首先将所有逻辑放在控制器内部,我看不到Model的任何用途,尤其是Active-Record。我们已经有了一种非常强大且易于使用的语言来与数据库进行通信,对吗?它叫做SQL。对我来说,当模型像活动记录一样实现时,它的用处取决于你是否希望你的应用程序适合多个数据库。
所以我要问的是,如果您只使用一个数据库,为什么还要使用模型和Active-Records呢?为什么不只使用SQL?为什么额外的复杂层?你们有没有任何案例研究/现实生活中的故事,其中模型实际上可以做的事情比仅仅使用数据库类和SQL-away更好?
再次,如果我似乎如此无知,我很抱歉,但我真的不知道为什么模特很重要。谢谢你回答。
答案 0 :(得分:18)
首先,假设模型层必然使用某种ORM,以便抽象出SQL。事实并非如此:您可以创建一个模型层,它从Controller层松散耦合但紧密耦合到特定的DBMS,因此避免使用功能齐全的ORM。
有一些ORM库,如Hibernate(Java),NHibernate(.NET),Doctrine(PHP)或ActiveRecord-Rails(Ruby),它们可以为您生成所有实际的SQL语句;但如果您认为ORM是不必要的,并且您想手动定义所有SQL语句,请不要使用它们。
仍然,恕我直言, NOT 意味着您应该将所有与DB相关的逻辑放在控制器层中。这被称为“胖控制器”方法,它是一条多次导致臃肿,不可维护的代码的道路。您可以将它用于简单的CRUD项目,但除此之外的任何事情都需要存在真正的“模型”。
你似乎关心MVC。请阅读有关TDD的内容。一个聪明人曾经说过“legacy code is code without tests”。当您了解到自动化单元测试与“真实”代码一样重要时,您就会明白为什么企业应用程序中有这么多层,以及为什么您的模型层应该与Controller分开。尝试执行所有操作的代码块(表示,业务逻辑,数据持久性)根本无法轻松测试(也无法通过调试)。
修改强>
“模型”是一个有点模糊的术语。根据您所看到的位置,它可能意味着略有不同。例如,PHP e Ruby程序员经常将它用作Active Record的同义词,这是不准确的。其他一些开发人员似乎认为“模型”只是某种DTO,这也是不对的。
我更喜欢使用Wikipedia中所见的模型定义:
模型MVC的核心组件根据其问题域捕获应用程序的行为,与用户界面无关。该模型直接管理应用程序的数据,逻辑和规则。
因此,模型是大多数MVC应用程序中最重要,最重要的层。这就是为什么它通常分为子层:域,服务,数据访问等。模型通常是通过域暴露,因为在那里您可以找到控制器将调用的方法。但是数据访问层也属于“模型”。与数据持久性和业务逻辑相关的任何内容都属于它。
答案 1 :(得分:8)
这根本不是一个无知的问题!只是事实上你要求它而不是简单地忽略整个MVC理论而且随心所欲地做就好了。 : - )
回答你的问题:从概念上讲,模型只是为你的数据提供了一个很好的抽象。模型不是考虑“我如何编写这个内部联接以获得我需要的所有字段”,而是让您根据“我的应用程序的对象如何相互关联,它们如何交互以及如何进行交互”来思考从他们那里得到我需要的数据“。
与视图和控制器帮助您从逻辑中分离表示的方式相同,模型可以帮助您从应用程序的逻辑(从用户的角度来看)分离数据的详细信息,以及数据实际来自何处以及内部如何表示
给出一个更具体的例子(如果不是完全真实的):理论上,你可以用你通过SQL查询获取所有数据的方式编写整个应用程序。但是后来你意识到你想要使用一些noSQL(CouchDB等)引擎,因为你需要水平扩展。
使用模型(以及可以使用两种类型的存储的框架,当然:-)),您不必担心细节,因为所有重要数据都已通过模型以通用方式表示,视图和控制器都可以根据该表示进行操作。
没有它们,您可能不得不重写大量代码,以使您的数据获取适应新的后端。
而这只是在无聊的存储部分。使用纯SQL,定义应用程序对象(即业务逻辑)之间的交互要困难得多,因为您不会在SQL中执行此操作(可能无论如何)。
这不是一个完美的解释(远非它),但我希望它有所帮助。
答案 2 :(得分:6)
在大多数现实生活中,来自用户的数据不会直接进入数据库。
必须经常对其进行验证,过滤或转换。
模型层的作用通常是通过执行这些操作来确保数据正确地到达后端存储(通常是数据库),这些操作不应该是控制器(瘦控制器,胖模型)的责任,以及不是数据库引擎本身的责任。
换句话说,Model层负责 - 或者“知道” - 应该如何处理数据。
大多数现代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
这里,数据库无法处理几个数据有效性要求,不应在控制器中处理,因为这些要求中的任何修改都可能会破坏几个地方的代码。
因此,该模型是确保数据与您的域一致的最佳位置。
关于它还有很多话要说,但是我觉得在实践经验的推动下,抓住一个对我来说很重要的一点:)
答案 3 :(得分:3)
模型应包含所有逻辑。控制器仅负责与用户交互相关的逻辑。所有与域相关的功能(所谓的“业务逻辑”)都应该放在模型中并与控制器代码分离。像这样,您可以更好地分离关注点和代码可重用性。
例如,假设您正在编写一个应用程序,让用户输入有关自己的信息并接收饮食重新定位。
一方面,您可以将与用户提供的数据相关的代码放入模型部分的饮食再处理列表中。这包括数据库访问,但也包括与问题(问题域)相关的任何计算,算法和处理。
另一方面,您将代码记录在用户中,在控制器中显示表单,收集表单数据,验证它。这种方式,例如,您可以稍后向您的应用程序添加api(使用不同的代码进行身份验证,从用户获取数据,验证等)并重复使用代码生成结果(来自模型)。
这只是该模型有用的一个例子。
答案 4 :(得分:1)
我始终将模型与数据联系起来,无论数据存在于何处或如何表示。在MVC V中,显示数据和C句柄的变化。即使您在控制器内的HashMap中显示所有数据; HashMap将被称为模型。