为什么Qt会滥用模型/视图术语?

gor*_*orn 101 model-view-controller qt

我认为Qt中使用的模型/视图控件的术语是有缺陷的.在他们的解释页面上,他们说,他们通过合并View和Controller将MVC简化为MV,他们给出了以下图片:

解释Qt MVC的图片

不过我认为,他们错误地命名了对象的角色,我认为,

  1. 他们所谓的View with merged Controller实际上只是一个View.
  2. 他们所谓的模型实际上只是控制器.
  3. 如果你真的想拥有一个模型,那么它就是"数据"所在的地方.

我说的是你在应用程序中使用Qt模型/视图组件的通常和理智的方式.原因如下:

  1. 这通常是Qt组件,它按原样使用,不添加任何特定于您的对象的Controller逻辑)
  2. 这不是一个模型,只是因为你应该实现几个Qt方法,如rowCount,columnCount,data等,这与你的模型无关.事实上,控制器中有典型的模型方法.当然,你可以在这里实现控制器模型逻辑,但首先它将是非常糟糕的代码设计,其次你将控制器和模型合并而不是控制器和视图.
  3. 如上所述2.如果你想分离模型逻辑,它肯定不是图片上的蓝色框,而是虚线"数据"框(当然是与真实数据通信).

Qt在他们的术语中是错误的,还是只是我不懂的?(顺便说一句:这不是学术问题的原因是我已经开始按照命名开始对我的项目进行编码,我很快就发现,代码显然不对.只有在我意识到之后,我应该不要尝试将模型逻辑放在他们称之为Model的模型中)

lee*_*mes 82

简短的回答

Qt的MVC仅适用于一种数据结构.在谈论MVC 应用程序时,你不应该考虑QAbstractItemModelQListView.

如果你想为你的整个程序使用MVC架构,Qt就没有这样一个"庞大"的模型/视图框架.但是对于程序中的每个列表/数据树,您可以使用Qt MVC方法,该方法确实在其视图中具有控制器.的数据是内或模型的外部; 这取决于您使用的模型类型(自己的模型子类:可能在模型中;例如QSqlTableModel:外部(但可能在其中缓存)模型).要将模型和视图放在一起,请使用自己的类,然后实现业务逻辑.


答案很长

Qt的模型/视图方法和术语:

Qt 为他们的模型提供了简单的视图.它们内置了一个控制器:选择,编辑和移动项目是大多数情况下控制器"控制"的东西.也就是说,解释用户输入(鼠标点击和移动)并向模型提供适当的命令.

Qt的模型确实是具有基础数据的模型.抽象模型当然不包含数据,因为Qt不知道你想如何存储它们.但是,通过将数据容器添加到子类并使模型接口访问数据,可以将QAbstractItemModel扩展到您的需求.所以事实上,我认为你不喜欢这个,问题是需要对模型进行编程,以便在数据结构中如何访问和修改数据.

在MVC术语中,模型包含数据逻辑.在Qt中,取决于您是否在模型中包含一些业务逻辑或将其放在外部,作为自己的"视图"取决于您.它甚至不清楚逻辑意味着什么:选择,重命名和移动项目?=>已经实施.用它们做计算?=>将其放在模型子类的外部或内部.从/向文件存储或加载数据?=>将它放在模型子类中.


我的个人意见:

这是很难提供良好一般的MV(C)系统程序员.因为在大多数情况下模型很简单(例如只有字符串列表)Qt还提供了一个现成的QStringListModel.但是,如果您的数据比字符串更复杂,那么您可以通过Qt模型/视图界面来表示数据.例如,如果您有一个包含3个字段的结构(让我们说具有名称,年龄和性别的人),您可以将3个字段分配给3个不同的列或3个不同的角色.我不喜欢这两种方法.

我认为Qt的模型/视图框架仅在您想要显示简单数据结构时才有用.如果数据是自定义类型或结构不在树或列表中(例如图形),则变得难以处理.在大多数情况下,列表足够,甚至在某些情况下,模型应该只保留一个条目.特别是如果你想模拟一个具有不同属性的单个条目(一个类的一个实例),Qt的模型/视图框架不是将逻辑与用户界面分开的正确方法.

总而言之,我认为Qt的模型/视图框架是有用的,当且仅当您的数据被Qt的查看器小部件之一查看时.如果您要为仅包含一个条目的模型编写自己的查看器(例如应用程序的设置),或者您的数据不是可打印类型,则完全没用.


我如何在(更大)应用程序中使用Qt模型/视图?

我曾经(在一个团队中)写过一个使用多个Qt模型来管理数据的应用程序.我们决定创建一个DataRole用于保存每个不同模型子类的不同自定义类型的实际数据.我们创建了一个外部模型类,称为包含Model所有不同的Qt模型.我们还创建了一个外部视图类,称为View包含连接到模型内的窗口(窗口小部件)Model.所以这种方法是扩展的Qt MVC,适合我们自己的需要.两者ModelView类本身与Qt MVC没有任何关系.

我们把逻辑放在哪里了?我们创建了一些类,它们通过从源模型中读取数据(当它们发生更改时)并将结果写入目标模型来对数据进行实际计算.从Qt的角度来看,这个逻辑类是视图,因为它们"连接"到模型(不是用户的"视图",而是应用程序的业务逻辑部分的"视图").

控制器在哪里?在最初的MVC术语中,控制器解释用户输入(鼠标和键盘)并向模型发出命令以执行所请求的操作.由于Qt视图已经解释了重命名和移动项目等用户输入,因此不需要这样做.但我们需要的是对用户交互的解释,这超出了Qt视图.

  • @smerlin:我认为这不对.QListView和QTreeView都只需要一个QAbstractItemView接口,这意味着它的自定义子类,或者像QStandardItemModel这样的具体类应满足两者的要求.您可以驾驶树并列出一个模型. (2认同)

Til*_*ilo 76

我同意你的看法,Qt的命名具有误导性.然而,在我看来,问题不仅仅是Qt,而是由所有框架共享,这些框架允许我们在实现UI时遵循关注点分离的原则.当有人提出这样一个框架,并找到一种保持"事物"分离的好方法时,他们总是觉得有必要拥有他们称之为"模型"的模块和其他他们称之为"视图"的模块.多年来我一直在使用这些框架:

  • MFC
  • Qt的
  • 摇摆
  • SWT
  • WPF与MVVM

如果比较在这些框架中使用术语"模型"和"视图"的方式,以及"视图","模型"和"控制器"(如果有)中的类具有哪些职责,您将发现存在很大差异.对不同的概念和术语进行比较肯定是有用的,这样人们从一个框架转换到另一个框架就有机会保持理智,但这需要大量的工作和研究.好的阅读是Martin Fowler的概述.

既然有这么多不同的想法什么 MVC模式可以关注一下,哪一个是正确的?在我看来,当我们想知道如何"正确"实现它时,应该转向发明MVC的人.在最初的smalltalk论文中,它说:

该视图管理分配给其应用程序的位图显示部分的图形和/或文本输出.控制器解释来自用户的鼠标和键盘输入,命令模型和/或视图适当地改变.最后,该模型管理应用程序域的行为和数据,响应有关其状态的信息请求(通常来自视图),并响应指令以更改状态(通常来自控制器).

鉴于此,我将回答你的三个主要问题:

  1. 实际上,Qt组件"管理图形输出",并"解释鼠标和键盘输入",因此就上面的定义而言,它确实可以被称为合并视图和控制器.
  2. 我同意你/将被迫合并Controller和Model(再次针对上面的定义).
  3. 我再次同意.模型应该只管理应用程序域的数据.这就是他们所谓的"数据".显然,例如处理行和列通常与我们的应用程序域无关.

它离开了我们的哪里?在我看来,最好弄清楚Qt在使用术语"模型"和"视图"时的真正含义,并在我们用Qt编程时使用它们的方式.如果你继续被打扰,它只会减慢你的速度,而Qt中设置的方式确实可以实现优雅的设计 - 这比他们的"错误"命名惯例更重要.

  • 我想说委托是Qt的控制器,因为委托接收输入并将其发送到模型,该模型通过信号更新视图。 (2认同)

arn*_*rnt 12

术语不对或错,它是有用的或无用的.

您可能会稍微改变一下这个问题并询问为什么Qt不再对MVC友好.答案是,早期的Qt开发人员认为在GUI应用程序中将V与C分离会导致坏的V和C两者.QWidget的设计试图让鼠标输入插入与像素输出决策紧密结合变得简单,你可以看到这不是通向MVC的道路.