Почему Qt неправильно использует терминологию модели / представления?

104

Я думаю, что терминология, используемая в Qt с элементами управления модель / представление, ошибочна. На своей странице объяснения они заявляют, что они упростили MVC до MV, объединив View и Controller, и дают следующую картину:

изображение, объясняющее Qt MVC

Однако я думаю, что они неправильно назвали роли объектов, и я думаю, что

  1. То, что они называют представлением с объединенным контроллером, на самом деле является только представлением.
  2. То, что они называют моделью, на самом деле является только контроллером.
  3. Если вы действительно хотите иметь модель, она будет где-то там, где находятся их «Данные».

Я говорю об обычном и разумном способе использования компонента модель / представление Qt в своем приложении. Вот причины:

  1. Обычно это компонент Qt, который используется как есть, без добавления какой-либо логики контроллера, специфичной для ваших объектов)
  2. Вряд ли это Модель, просто потому, что вы должны реализовать несколько методов Qt, таких как rowCount, columnCount, data и т. Д., Которые не имеют ничего общего с вашей моделью. На самом деле в контроллерах есть типичные методы модели. Конечно, вы можете реализовать здесь логику контроллера и модели, но, во-первых, это будет довольно плохой дизайн кода, а во-вторых, вы должны объединить контроллер и модель, а не контроллер и представление, как они заявляют.
  3. Как сказано в причине 2. Если вы хотите разделить логику модели, это, конечно же, не синий прямоугольник на картинке, а пунктирный прямоугольник «Данные» (конечно же, сообщающийся с реальными данными).

Qt ошибается в их терминологии, или это просто я не понимаю? (Кстати: причина, по которой это не академический вопрос, заключается в том, что я начал кодировать свой проект, следуя их названию, и вскоре обнаружил, что код явно неправильный. И только после этого я понял, что я должен не пытайтесь поместить логику модели в то, что они называют моделью)

горн
источник
1
MFC установил стандарт для двухкомпонентного графического интерфейса модели / представления с CDoc и CView - нет причин, по которым конкретный MVC является «правильным»
Мартин Беккет,
@Martin B: Я посмотрю на MFC, однако, даже если есть разные модели MVC, я думаю, что они должны быть последовательными в своей терминологии, и я думаю, что я представил веские аргументы, почему используемая терминология не согласуется в этом конкретном случае. Они просто заявляют, что они объединили View и Controller, но я считаю, что в данном случае это просто вводит в заблуждение. Я не думаю, что существует модель MVC, в которой вся логика приложения, будь то представление или логика модели, должна быть помещена в один объект с именем Model.
gorn
1
@Martin B: Также согласно терминологии qt все модели имеют общий api, который не имеет ничего общего со структурой модели, но имеет все, что связано с общей структурой контроллера, что явно указывает на то, что называть ее моделью неправильно. Я не говорю, что существует ОДНА правильная модель MVC, но это не означает, что что-либо можно назвать моделью MVC. Может быть, в MFC тоже есть недостатки, и я могу взглянуть на это, но меня больше интересует Qt, который правильно понимает, тот MFC, который я не собираюсь использовать. У вас есть хорошая ссылка, где объясняется разделение модели / представления MFC?
gorn 05
1
Терминология MVC ни в коем случае не согласована единогласно, поэтому ваш вопрос можно считать аргументированным. Однако многие согласятся с отличной работой, проделанной Мартином Фаулером ( martinfowler.com/eaaDev/index.html ). Обычно контроллер обрабатывает ввод данных пользователем, и в этом смысле виджеты Qt определенно объединяют представление и контроллер.
Арнольд Спенс
1
Я понимаю, что MVC имеет много разновидностей, но это не означает, что что-то может быть MVC. Qt перешел черту, и я привел несколько причин. Мартин Фаулер действительно объясняет различные типы MVC, но ни один из них не достаточно похож на то, что Qt произносит как MVC. Наиболее похожим является martinfowler.com/eaaDev/PresentationModel.html , но в нем проводится различие между частью Presentation Model = Controller (взаимодействие с пользователем) и Model (логика данных). Итак, хотя нет точного определения MVC, Qt не следует ни одному из них. Если вы можете дать мне ссылку на такое определение, сделайте это.
gorn

Ответы:

78

Я согласен с вами в том, что название Qt вводит в заблуждение. Однако, на мой взгляд, проблема заключается не только в Qt, но и во всех фреймворках, которые позволяют нам придерживаться принципа разделения задач при реализации наших пользовательских интерфейсов. Когда кто-то придумывает такую ​​структуру и находит хороший способ разделить «вещи», он всегда чувствует себя обязанным иметь модули, которые они называют «Модель», и другие, которые они называют «Представлением». На протяжении многих лет я работал с этими фреймворками:

  • MFC
  • Qt
  • Качели
  • SWT
  • WPF с MVVM

Если вы сравните, как термины «Модель» и «Представление» используются в этих фреймворках, и какие обязанности имеют классы в «Представлении», «Модель» и «Контроллер» (если он есть), вы увидите обнаружите, что есть очень большие различия. Безусловно, было бы полезно сравнить различные концепции и терминологию, чтобы люди, переходящие с одного фреймворка на другой, имели шанс оставаться в здравом уме, но для этого потребуется много работы и исследований. Хорошее прочтение - обзор Мартина Фаулера .

Поскольку существует так много различных идей , что шаблон MVC может выглядеть, какой из них правильный? На мой взгляд, следует обращаться к людям, которые изобрели MVC, когда мы хотим знать, как это должно быть «правильно» реализовано. В оригинальной статье о smalltalk сказано:

Представление управляет графическим и / или текстовым выводом части растрового изображения, выделенной его приложению. Контроллер интерпретирует ввод данных с клавиатуры и мыши от пользователя, отдавая команду модели и / или представлению на необходимые изменения. Наконец, модель управляет поведением и данными домена приложения, отвечает на запросы информации о его состоянии (обычно из представления) и отвечает на инструкции по изменению состояния (обычно от контроллера).

В свете этого я бы ответил на ваши три основные проблемы следующим образом:

  1. Фактически, компонент Qt «управляет графическим [...] выводом» и «интерпретирует вводы с помощью мыши и клавиатуры», так что его действительно можно назвать объединенным представлением и контроллером в отношении определения выше.
  2. Я согласен с тем, что вы вынуждены / будете вынуждены объединить Контроллер и Модель (опять же в отношении определения выше).
  3. Я снова согласен. Модель должна управлять только данными домена приложения . Это то, что они называют «данными». Очевидно, что работа со строками и столбцами, например, обычно не имеет ничего общего с областью нашего приложения.

Куда он нас денется? На мой взгляд, лучше всего понять, что на самом деле означает Qt, когда используются термины «Модель» и «Представление», и использовать эти термины в их манере, пока мы программируем с Qt. Если вы продолжаете беспокоиться, это только замедлит вас, а то, как все устроено в Qt, позволяет элегантный дизайн, который весит больше, чем их «неправильные» соглашения об именах.

Тило
источник
2
Я бы сказал, что делегат - это контроллер Qt, поскольку делегаты получают и отправляют ввод в модель, которая обновляет представление через сигналы.
Peregring-lk
83

Короткий ответ

Qt MVC применяется только к одной структуре данных . Говоря о приложении MVC, не следует думать о QAbstractItemModelили QListView.

Если вам нужна архитектура 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, адаптированный к нашим собственным потребностям. Оба Modelи Viewклассы сами по себе не имеют ничего общего с Qt MVC.

Куда мы поместили логику ? Мы создали классы, которые выполняли фактические вычисления с данными, считывая данные из исходных моделей (когда они менялись) и записывая результаты в целевые модели. С точки зрения Qt, эти классы логики будут представлениями, поскольку они «подключаются» к моделям (не «представление» для пользователя, а «представление» для части бизнес-логики приложения).

Где контроллеры ? В исходной терминологии MVC контроллеры интерпретируют пользовательский ввод (мышь и клавиатура) и дают модели команды для выполнения запрошенного действия. Поскольку представления Qt уже интерпретируют вводимые пользователем данные, такие как переименование и перемещение элементов, в этом не было необходимости. Но нам нужна была интерпретация взаимодействия с пользователем, выходящая за рамки представлений Qt.

Leemes
источник
Больше всего раздражает то, что вам нужно реализовать совершенно разные классы модели Qt в зависимости от того, какое представление вы хотите. Модель для представления списка не будет должным образом поддерживать представление в виде дерева, и наоборот. Каноническая модель MVC может поддерживать множество различных типов представлений.
smerlin
3
@smerlin: Не думаю, что это правильно. И QListView, и QTreeView требуют только интерфейса QAbstractItemView, а это означает, что пользовательский подкласс этого или конкретный класс, такой как QStandardItemModel, должен выполнять это требование для обоих. Вы можете построить дерево и перечислить одну модель.
jdi
1
@jdi: есть случаи, когда ваши данные представляют собой и список, и дерево ... например, вы можете отобразить свою файловую систему в виде дерева или все файлы в виде списка. Модели Qts не позволяют этого должным образом. Реализация QAbstractItemModel, поддерживающая древовидные представления, позволяет отображать только все файлы / каталоги в вашем корневом каталоге в виде списка, но вы не можете отображать все файлы в виде списка. И не говорите, что отображение данных дерева в виде списка бесполезно. Например, вы можете легко отсортировать их, чтобы найти файл с наибольшим размером файла, если вы отображаете свои файлы в виде списка, древовидные представления этого не позволят.
смерлин
1
Тем не менее, прокси-модель больше относится к вашему представлению (поскольку она изменяет способ просмотра данных ) и, следовательно, должна принадлежать вашему представлению. Если вы прочитали мой длинный ответ: в «большой» Viewкласс вам следует добавить модель прокси, которая имеет модель дерева в качестве базовой модели и используется представлением списка вашей файловой системы. Как вы говорите: не должно быть двух моделей для одних и тех же данных. Никогда! (Но прокси-модели не считаются отдельными моделями.)
leemes
1
@SamPinkus Это потому, что на этот вопрос нет однозначного ответа « да» или « нет» . Кроме того, существуют различные реализации QAbstractItemModel, некоторые из которых являются моделями в смысле MVC, а некоторые нет.
leemes
12

Терминология неправильная или неправильная, полезная или бесполезная.

Вы можете немного изменить вопрос и спросить, почему Qt не более дружелюбен к MVC. Ответ заключается в том, что первые разработчики Qt полагают, что разделение V и C в приложениях с графическим интерфейсом создает плохие V и C. Дизайн QWidget пытается упростить привязку взаимодействия ввода мыши с решениями вывода пикселей, и вы можете видеть, что это не путь к MVC.

арнт
источник
Я понимаю вашу точку зрения, и в основном я БУДЕН бы спросить, почему Qt не более дружелюбен к MVC, но это очень сложно сделать, когда терминология MVC, используемая в документации Qt, ОТЛИЧАЕТСЯ от того, что обычно используется MVC (как я объяснил в вопросе). И когда есть широко используемая терминология, и кто-то использует ее совсем не так, как в остальном мире, я склонен думать, что она не только бесполезна, но и просто НЕПРАВИЛЬНА и сбивает с толку (эта путаница заставила меня задать вопрос в первом место). Мне было бы очень интересно, если у вас есть какие-либо ссылки на эти вещи, которые где-то обсуждаются или объясняются. Спасибо
gorn
Я не могу ничего сказать о том, почему документы Qt теперь говорят о MVC именно так, как они это делают. Я давно ушел из Trolltech и озадачен некоторыми вещами, которые были сделаны с документацией с тех пор, как я ушел. (Хотя в моем блоге я иногда немного разглагольствую об этом.)
arnt
У вас есть представление о том, как терминология MVC согласована в Qt. Было ли оно использовано при написании кода или только позже в процессе документирования.
gorn
Мы не использовали слово «MVC» в документации Qt, пока я работал в Trolltech. В общем, я считаю, что лучше документировать то, что есть, а не писать о том, чего нет. Тем не менее, более чем на Gitorious вы можете узнать, кто добавил , что текст и добавить , что человек непосредственно.
arnt
1
Другой комментарий. Мы обсуждали MVC во время разработки и фразу ранней реализации Qt (когда Trollech была компанией из трех человек), и мы оценили инструментарий GUI, который использовал MVC «правильно», я не могу вспомнить его название. По нашему мнению, этот инструментарий было ужасно использовать, и что во многом причиной этого был MVC.
arnt
3

Поскольку функция модели предназначена для ответа на запросы информации, я думаю, что нет ничего плохого в определении таких методов, как rowCount, columnCountи т. Д. Я думаю, что модель - это своего рода оболочка для источника данных (независимо от того, что это таблица SQL или просто массив) , он предоставляет данные в стандартной форме, и вы должны определять методы в зависимости от структуры вашего источника данных.

Дмитрий
источник
2

Я считаю, что их терминология верна ... хотя я считаю, что в реальных приложениях очень легко размыть границы между моделью, представлением и контроллером в зависимости от вашего уровня абстракции: представление одного уровня может быть моделью более высокого уровня.

Я чувствую, что путаница возникает из-за их класса QAbstractModelItem. Этот класс не является элементом модели, а скорее является интерфейсом к модели. Чтобы их классы представления взаимодействовали с моделью, им пришлось создать общий абстрактный интерфейс для модели. Однако модель может быть отдельным элементом, списком элементов, таблицей с двумя или более измерениями элементов и т. Д .; поэтому их интерфейс должен поддерживать все эти варианты моделей. По общему признанию, это делает элементы модели довольно сложными, и связующий код, заставляющий их работать с реальной моделью, похоже, немного расширяет метафору.

Крис Морлиер
источник
Хотя я согласен с вами в отношении класса QAbstractModelItem, я также думаю, что даже без этого усложнения их MVC неправильно названы. Не могли бы вы объяснить, почему вы считаете их терминологию правильной. Я хотел бы услышать, почему я не прав ни в одном из трех своих аргументов.
gorn
0

Я думаю, что ... То, что они называют Моделью, на самом деле только Контроллер.

Нет, их «модель» - это точно не контроллер.

Контроллер является частью видимых пользователем элементов управления, которые изменяют модель (и, следовательно, косвенно изменяют представление). Например, кнопка «удалить» является частью контроллера.

Я думаю, что часто возникает путаница, потому что многие видят что-то вроде «контроллер изменяет модель» и думают, что это означает изменяющие функции в их модели, такие как метод «deleteRow ()». Но в классическом MVC контроллер - это именно часть пользовательского интерфейса. Методы, которые изменяют модель, являются просто частью модели.

С момента изобретения MVC различие между контроллером и представлением становится все более напряженным. Подумайте о текстовом поле: оно одновременно показывает вам текст и позволяет редактировать его, так что это вид или контроллер? Ответ должен заключаться в том, что он является частью обоих. Когда в 1960-х годах вы работали над телетайпом, различие было более четким - подумайте ed- но это не значит, что тогда для пользователя все было лучше!

Это правда, что их QAbstractItemModel находится на более высоком уровне, чем модель обычно. Например, элементы в нем могут иметь цвет фона (технически кисть), что явно является атрибутом вида! Итак, есть аргумент, что QAbstractItemModel больше похож на представление, а ваши данные - это модель. На самом деле это что-то среднее между классическими значениями представления и модели. Но я не понимаю, как это контроллер; во всяком случае, это виджет QT, который его использует.

Артур Такка
источник