MVC不是OOP吗?


61

OOP背后的主要思想是统一单个实体(对象)中的数据和行为。在过程编程中,有数据和修改数据的单独算法。

在“模型-视图-控制器”模式中,数据和逻辑/算法分别放置在不同的实体中,分别是模型和控制器。在等效的OOP方法中,模型和控制器不应该放在同一逻辑实体中吗?


11
为什么它们需要在同一逻辑实体中?您尚未说明为什么这样做会更有优势,或者OOP为何会决定这种安排。
罗伯特·哈维

26
好吧,业务逻辑进入模型,而不是控制器。控制器实际上只是将视图和模型粘合在一起的一个中介。因此,在模型中,您将数据和行为放在同一位置。
罗伯特·哈维

2
什么?统一数据和行为正是OOP的全部意义所在。
安迪

3
OOP关于将实现与接口分离。接口与行为有更多关系,而实现与数据有更多关系(这就是数据倾向于被隐藏的原因)。因此,OOP并不是要统一数据和行为,而是要将它们分开。
哈兹(Kaz)2012年

5
无论如何,您都不想将所有数据和行为归为一类。OOP程序使用多个类来创建对象框架。而且无论如何,如果某些事情是“反OOP”,那可能是一件好事。OOP不是万能的。OOP彻头彻尾糟透了。现在该克服OOP了。
哈兹(Kaz)2012年

Answers:


44

MVC是UI结构的关注点分离中的一项练习。这是一种防止由于呈现未与内容分离而在用户界面中发生的复杂性的方法。

从理论上讲,所有对象都可以具有对包含的数据进行操作的行为,并且数据和行为保持封装状态。实际上,给定的OOP对象可能具有或不具有与其数据相对应的逻辑,或者根本没有任何逻辑(例如,数据传输对象)。

在MVC中,业务逻辑进入模型,而不是控制器。控制器实际上只是将视图和模型粘合在一起的一种过渡。因此,在模型中,您可以将数据和行为放在同一位置。

但是,即使这种安排也不能保证严格的数据/行为融合。仅包含数据的对象可以由仅包含逻辑的其他类进行操作,这是OOP的完全可接受的用法。


我给你一个具体的例子。这有点做作,但是假设您有一个Currency对象,并且该对象可以用与美元挂钩的任何可用货币表示自己。因此,您将拥有如下方法:

public decimal Yen { get { return // dollars to yen; } }
public decimal Sterling { get { return // dollars to sterling; } }
public decimal Euro { get { return // dollars to euro; } }

...并且该行为将与Currency对象一起封装。

但是,如果我想将货币从一个帐户转移到另一个帐户或存入某种货币怎么办?该行为也将封装在Currency对象中吗?不,不会。钱包中的钱不能将自己从钱包中转入您的银行帐户;您需要一个或多个代理商(柜员或ATM)来协助将这笔钱存入您的帐户。

这样,该行为将被封装到一个Teller对象中,并且将接受CurrencyAccount对象作为输入,但是它本身将不包含任何数据,除了可能Transaction会帮助处理输入对象的一些局部状态(或对象)。


以及应Teller放在哪个实体/包装中?是Controller从哪里Teller's调用方法的,还是Model因为是业务逻辑的一部分?
m3th0dman '10 -10-11

Teller进入Model,尽管可以从控制器调用它。它是业务领域的一部分。
罗伯特·哈维

我一直认为,将模型用于业务规则使MVC成为半有效的模式。将模型用于实际应用程序的适配器,并使控制器在适配器和视图之间进行中介,对于实现SoC总是更加有效。
Yam Marcovic

@YamMarcovic:我不确定你的意思。该模型是一个包罗万象的东西。实际上,业务规则通常放置在其自己的服务层中,但仍被视为模型的一部分(例如,您不会在单个控制器方法中编码特定的业务规则)。您认为控制器之间是对的。
罗伯特·哈维

4
我认为大多数人对MVC的理解是错误的,仅仅是因为对MVC的理解是关于“业务逻辑”的含义的过于广泛的假设。如果您无法弹出模型并在具有相同业务目标但通过具有完全不同的应用程序逻辑的控制器来实现非常不同的体系结构的全新应用程序中进行很少甚至没有修改,就可以使用它,那您做错了海事组织。当然,将视图从其他所有内容的组合中分离出来仍然具有价值,但是C作为轻量级构造使我震惊,因为它缺少分离的关键点。
埃里克·雷彭

73

MVC工作在很多抽象比单个对象的较高水平,而事实上这三个(模型,视图和控制器)将通常由多个对象,每个有两个数据和行为。

封装数据和行为的对象通常是程序的一个很好的基本构建块,并不意味着它是所有抽象级别和所有目的的最佳模式。


面向对象的方法可以扩展抽象级别。例如,请参阅域驱动设计背后的原因,它的出现是因为经典的分层体系结构不是OOPish,而是过程性的。这发生在比MVC更高的抽象层次上。
m3th0dman 2012年

6
@ m3th0dman:您的发言是广泛而笼统的。如何讨论具体细节,例如MVC如何消除Winforms或Webforms的意大利面条式代码梦night?
罗伯特·哈维

3
@ m3th0dman:这是DDD的非常简单的表征。
Michael Borgwardt 2012年

1
@RobertHarvey要确定您与MVC为何好相反,因为它消除了意大利细面条并不是真正的竞赛。我同意,但是我倾向于看到MVC也以过程模式实现。因此,我认为这是一个相关的问题,或更确切地说,可能要问的问题是“人们多长时间执行一次MVC?”
吉米·霍法

1
@Robert Harvey问题的目的不是关于MVC的好坏。这是关于基于或不基于面向对象原则的事实。
m3th0dman 2012年

71

OOP并不限制每个都有自己的数据和行为的对象之间的交互。

想一想一个蚂蚁和一个蚁群的类比:单个蚂蚁的行为(整日奔跑,带来食物)不同于整个殖民地的行为(找到最理想的地方,制造更多的蚂蚁)。MVC模式描述了所需的蚁群社会结构,而OOP则指导了单个蚂蚁的设计。


5
+1:我通常不喜欢通过类比进行解释,但是这一点很棒。
Michael Borgwardt 2012年

@Caleb这是一个很好的观点,非常感谢!
dasblinkenlight 2012年

19

OOP还涉及关注点分离,即分离不同对象中的不同角色/职责。

MVC分为以下几个部分:

  • 模型:数据及其业务逻辑
  • 视图:数据表示
  • 控制器:模型与视图之间的协调。

因此,这些责任显然是不同的,并且确实应该分为多个实体。


确实,单一责任原则有助于有效地使用OOP,但我认为说“ OOP也是关于单一责任原则”的说法很过分。这似乎是落后的。
Caleb 2012年

@Caleb是的,我明白您的意思。也许可以改写,但您明白了。
marco-fiset 2012年

18

在“模型-视图-控制器”模式中,数据和逻辑/算法分别放置在不同的实体中,分别是模型和控制器。

模型和控制器是两个不同的角色。模型既具有状态又具有逻辑,而控制器既具有状态又具有逻辑。他们进行通信的事实并不会破坏两者的封装-控制器不知道或不在乎模型如何存储其数据,或者在控制器检索或更新数据的某些部分时模型对数据的处理方式。模型不知道或不在乎控制器如何使用模型提供的数据。

这样想:如果对象不能在不破坏封装的情况下来回传递数据,那么实际上您只能有一个对象!

在等效的OOP方法中,模型和控制器不应该放在同一逻辑实体中吗?

MVC 一种OOP方法-具体地说,它是决定如何使用对象有效组织程序的秘诀。而且没有,模型和控制器应该不是同一个实体。控制器允许模型和视图之间的分离。保持模型和视图彼此独立,使其更具可测试性和可重用性。


我希望控制器具有逻辑但几乎没有状态。您认为控制器具有哪种状态?
马修·弗林

1
@MatthewFlynn对于初学者,控制器需要了解视图和模型。除此之外,它取决于我们在谈论什么MVC的特殊味道,但一般一个控制器可以保持状态有关如何应该显示的信息(例如,当前的选择),而该模型涉及什么信息显示。
卡勒布(Caleb)2012年

1
@MattFenwick这就是我所说的“风味”……您在控制器中存储的内容以及模型中的内容完全取决于口味和约定。在Cocoa / Cocoa Touch中,通常将诸如当前选择甚至用户首选项之类的内容保留在控制器中。在某些Web框架中使用的MVC几乎可以将所有内容放入模型中,而将很少内容放入控制器中。YMMV。
迦勒2012年

4
@MatthewFlynn大多数人都会同意您的看法,但IMO,人们将业务逻辑视为比其应有的范围更广的范畴。控制器处理人们经常与业务逻辑相混淆的应用程序逻辑。在理想的关注点分离中,我应该能够在服务于相同业务目标的完全不同的应用程序体系结构中重用模型对象,而无需修改业务对象。新应用程序所需要做的就是使用该接口,并对返回和处理的数据和事务进行自己的处理。
埃里克·雷彭

1
@MattFenwick:考虑多用户应用程序。在模型和控制器之间划清界限的明显点是,模型处理共享状态,而控制器处理局部状态。当前选择是本地的,因此它进入控制器。
Jan Hudec

4

MVC是一种模式,它描述了对象交互的明智方式。它本身不是元类。那时,OO是关于描述实体的行为和数据以及所述实体如何交互的。这与将整个系统统一为一个庞大的对象无关。


2

控制器不代表模型的行为。控制器一共代表整个应用程序的行为-用户可以做什么以及用户可以看到什么。

将控制器和模型视为一个是错误的。它们具有不同的目的,不同的语义,因此不应统一在一个对象中。


2

模型层不仅是数据,而控制器层仅仅是逻辑。

出于其目的,控制器层将具有完整的对象集合。将有一些对象用于从视图中接收输入,以及将输入转换为模型可以处理的形式。Struts Java框架在其Action / Form模型中有一个很好的例子。表单将使用用户的输入进行填充,然后传递给操作。动作将获取该数据并使用它来操纵模型。

同样,模型层也不是完全由数据组成。例如,以一个User对象为例,您可能需要从数据库中获取用户的代码,或者需要将用户与订单相关联或验证用户的地址在公司服务范围内的代码...您将获得图片。这不是控制器逻辑。它是业务逻辑,导致许多人将其Model层划分为多个层,例如业务逻辑的Service或Manager层,用于数据库访问的DAO(数据库访问对象)层等。

MVC并不是组织单个Model操作的方法。它的工作水平更高,它是一种组织如何访问应用程序的方法。视图用于显示数据和用于操作数据的人工操作,控制器用于在用户操作和各种视图之间进行转换,模型用于存储业务数据及其存在的业务原因。


2

OOP的重点是将属于一起的数据和功能组合在一起。基于某些数据的计算并不总是属于该数据。

在MVC中,显示一条数据(视图)的功能与该数据(模型)分开。这是为什么?特别是这样,无需更改基础数据即可更改显示逻辑。每当需要对同一数据进行不同的表示时,或者在显示硬件的特性发生变化时,或者从Windows切换到Linux时,都可以轻松更改视图。或者当您希望两个人使用两种不同的方式查看同一数据时。

MVC与OOP并不冲突-它实际上是从正确应用面向对象原理而派生的。


0

我相信您将绑定到模型对象的持久性数据与模型进行交互的数据库中的应用程序数据混淆了。模型包含用于处理数据库和进行事务的业务逻辑和规则。它可能会设置和检查内部状态标志,例如今天是否有销售,用户是否具有VIP资格,然后在需要访问,设置或操纵数据或进行购买时相应地分支逻辑。当我们讨论对象封装方法和持久性值或数据的封装时,就是在谈论这些标志。

正如模型对象维护用于建立正在运行的业务规则的数据一样,IMO控制器应保留与应用程序的行为有关的更通用的应用程序状态数据,例如用户是否登录或是否拥有有效信用卡数据到位。模型方法将首先确定这些事物的状态,但是对于控制器来说,如果它们不适用于业务运营或数据交易方式,则维护与通用应用程序流相关的标志是有意义的。一旦确定它们尚未登录,就不要再通过用户状态检查来打扰模型,直到明确进行另一次登录尝试为止。

同样,使用适当的视图对象与在大多数服务器端Web框架中看到的更典型的HTML模板也是如此。加载用户的颜色首选项后,应该是保留该数据并在其上执行的视图。加载,验证和更改设置都是模型问题,但是只有在发生更改之前它们才是模型问题。

IMO,没有什么说控制器不能是将视图和模型作为内部聚合对象的复合对象。如果您像UI小部件工厂那样在较小的规模上应用MVC,这实际上是有道理的,因为控制器是将接口暴露给更高级别的应用程序对象的理想场所,同时掩埋了视图和模型如何交互的数据和逻辑细节。对于控制器应用程序实际上是最高级别对象的单一应用程序对象,这实际上没有任何意义。


0

据我了解;论据是基于组件的体系结构与OOP。而且,在没有参加宗教战争的情况下,我认为他们都在描述同一件事。只是从不同的角度看。

例如,OOP / OOD的全部目的是使您的代码更具模块化和可重用性。是?

这正是基于组件的体系结构的目标。因此,它们比其他任何东西都更相似。

我认为MVC只是OOP的自然演变,我敢说。一种更好的组织对象,关注点分离和代码重用的方法。


我想说MVC和基于组件的体系结构不是OOP方法领域的设计模式,而OOD / OOP只是关于如何使用无处不在的编程的一堆混乱和冲突。正确构造。比较这两类事物就像比较正方形和用来绘制正方形的笔。
艾里克·雷彭

-1

我参加这个聚会很晚,考虑我之前提出的所有答案,我承认我没有太多新意要提供。但是在我看来,问题不在于模式本身,而在于实现。MVC本身并不适合任何特定的方法。实际上,我可以很容易地以MVC模式构想面向过程的代码(这就是我的暗示)。

因此,我认为真正的问题是;使用MVC模式时,我们是否更倾向于使用过程代码?

(也许我会得到一些否定票?)


-1

不反,MVC也不需要OOP。

因为通常由类表示的控制器不保存任何数据。对于那些纯函数就足够了。

例如,如果您进一步将数据与行为分开,则可以说模型仅适用于数据库数据,每次调用它们的函数(负责数据操作)时,模型便会提取这些模型(而不是在实例中存储某种数据)字段)-然后您可以对模型说相同的内容。

更进一步,如果您采用应用程序的视图层并以类似的方式对其进行划分,那么您实际上将得出结论,即MVC与OOP无关,并且完全有可能仅使用过程方法来编写MVC实现而不会费劲。


哈哈,我看到有些人面对事实时感到痛苦。用OOP做自己的框架需要太多的努力吗?受不了失去的时间?最简单的答案是最好的。
luke1985 2014年

不知道为什么这个答案不好。他是说他们不相关,也不是“反”。似乎很准确。
mwilcox

-3

在我看来,OOP具有一个缺点,因为(数据和行为)被模制为一个实体(类),这显示出比凝聚力更多的耦合效应。另一方面,MVC具有包含以下内容的模型(Bean,DAO,其他逻辑类),指定控件必须如何运行的Controller和确定如何显示数据的Views以单独方式给出。基于此,无论项目规模太大,准备工作都可以很容易地作为单独的实体进行,而不是像OOP那样变得难以混合。就像分治制策略一样,问题以逻辑模式解决,而MVC最多也遵循这一点。


这只是您的意见,还是可以通过某种方式进行备份?
蚊蚋
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.