Чому Qt неправильно використовує модель / термінологію перегляду?


104

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

малюнок, що пояснює Qt MVC

Однак я думаю, що вони неправильно назвали ролі об'єктів, і я думаю, що

  1. Те, що вони називають Перегляд із об'єднаним контролером, насправді є лише Переглядом.
  2. Те, що вони називають Модель, насправді є лише контролером.
  3. Якщо ви дійсно хочете мати модель, вона буде десь там, де є їх "Дані".

Я говорю про звичайний і здоровий спосіб, коли ви використовуєте Qt модель / компонент перегляду у своєму додатку. Ось причини:

  1. Зазвичай це компонент Qt, який використовується як є, без додавання будь-якої логіки контролера, характерної для ваших об'єктів)
  2. Це навряд чи Модель, лише тому, що ви повинні реалізувати кілька методів Qt, таких як rowCount, columnCount, дані тощо, які не мають нічого спільного з вашою моделлю. Насправді є типові методи моделей, знайдені в контролерах. Звичайно, ви можете реалізувати тут і логіку контролера, і модель, але по-перше, це буде дуже поганий дизайн коду, а по-друге, ви б злили Controller і Model не Controller і View, як вони заявляють.
  3. Як сказано в причині 2. Якщо ви хочете розділити логіку моделі, це, безумовно, не синє поле на малюнку, а скоріше пунктирне поле "Дані" (повідомлення звичайно, звичайно).

Чи неправильно Qt в їх термінології, або це я просто не розумію? (BTW: Причина, чому це не академічне питання, полягає в тому, що я почав кодувати мій проект після їх найменування, і незабаром з’ясував, що код явно не вірно. Лише після цього, коли я зрозумів, що я повинен не намагайтеся вкласти логіку Model у те, що вони називають Model)


1
MFC встановив стандарт для 2-х частинної моделі / перегляду guis з CDoc та CView - немає причин, щоб конкретний MVC був "правильним"
Мартін Бекетт

@Martin B: Я буду дивитись на MFC, однак, навіть якщо існують різні моделі MVC, я думаю, що вони повинні відповідати своїй термінології, і я думаю, що я представив вагомі аргументи, чому використовувана термінологія не є узгодженою в цьому конкретному випадку. Вони просто заявляють, що вони поєднали View і Controller, але я річ, що це просто оманливий випадок. Я не думаю, що існує модель MVC, де вся логіка конкретної програми, будь то презентація або логіка моделі, повинна бути розміщена в одному об'єкті, який називається Model.
gorn

1
@Martin B: Також у термінології qt всі Моделі мають спільні api, що не мають нічого спільного з структурою Model, але все, що стосується загальної структури контролера, що явно означає, що невірно називати її Модель. Я не кажу, що Є ОДНА правильна модель MVC, але це не означає, що що-небудь можна назвати моделлю MVC. Можливо, він є недоліком і в MFC, і я можу поглянути на це, але мене більше цікавить Qt, щоб він зрозумів, що MFC, який я не збираюся використовувати. Чи є у вас хороша посилання, де пояснюється поділ моделі / перегляду MFC?
gorn

1
Термінологія MVC аж ніяк не одностайно узгоджена, тому ваше запитання можна вважати аргументативним. Однак багато хто погодиться з чудовою роботою, виконаною Мартіном Фаулером ( martinfowler.com/eaaDev/index.html ). Зазвичай контролер обробляє введення користувача, і в цьому сенсі Qt віджети, безумовно, поєднують перегляд і контролер.
Арнольд Спенс

1
Я розумію, що MVC має багато ароматів, але це не означає, що MVC може бути чим-небудь. Qt перетнув лінію, і я навів кілька причин. Мартін Фаулер пояснює різні типи MVC, але жоден з них не є досить подібним до того, що Qt вимовляє MVC. Найбільш схожим є martinfowler.com/eaaDev/PresentationModel.html , але це відрізняє Presentation Model = частина контролера (взаємодія з користувачем) та Model (логіка даних). Отже, хоча точного визначення MVC немає, Qt не дотримується жодного з них. Якщо ви можете надати мені посилання на таке визначення, будь ласка, зробіть це.
gorn

Відповіді:


78

Я згоден з вами, що ім'я Qt вводить в оману. На мою думку, однак, проблема полягає не лише в Qt, а поділяється всіма рамками, які дозволяють нам дотримуватися принципу розділення проблем при впровадженні наших інтерфейсів. Коли хтось придумує таку основу, і знаходить хороший спосіб розділити "речі", вони завжди відчувають обов'язок мати модулі, які вони називають "Модель" та інші, які вони називають "Перегляд". Протягом багатьох років я працював з цими рамками:

  • MFC
  • Qt
  • Гойдалка
  • SWT
  • WPF з МВВМ

Якщо ви порівняєте, як в цих рамках використовуються терміни "Модель" та "Вид" та які обов'язки мають класи в "Вид", "Модель" та "Контролер" (якщо такий є), виявляють, що існують дуже великі відмінності. Безумовно, було б корисно зіставити різні поняття та термінології, щоб люди, які переходили від однієї структури до іншої, мали шанс бути здоровими, але це вимагало б багато роботи та досліджень. Добре читати - огляд Мартіна Фаулера .

Оскільки існує так багато різних ідей , що шаблон MVC може виглядати, який з них правильний? На мою думку, до людей, які винайшли MVC, слід звертатися, коли ми хочемо знати, як воно має бути реалізовано «правильно». У оригінальному папері з невеликими розмовами написано:

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

У світлі цього я б відповідав твоїм головним проблемам таким чином:

  1. Насправді компонент Qt "керує графічним [...] виведенням" та "інтерпретує введення миші та клавіатури", тому його справді можна назвати об'єднаним представленням перегляду та контролера стосовно визначення, яке викладено вище.
  2. Я погоджуюся, що ви / були б змушені об'єднати контролер і модель (знову ж таки щодо визначення вище).
  3. Згоден, знову. Модель повинна керувати лише даними домену додатка . Це те, що вони називають «даними». Ясна річ, наприклад, що стосується рядків і стовпців, як правило, не має нічого спільного з нашим додатком.

Куди він нас залишає? На мою думку, найкраще розібратися, що насправді означає Qt, коли використовуються терміни «Модель» та «Вид», і використовувати терміни у їхньому манері, поки ми програмуємо з Qt. Якщо ви продовжуєте турбуватись, це лише сповільнить вас, а спосіб налаштування в Qt дозволяє вишуканий дизайн - який важить більше, ніж їх "неправильні" умови іменування.


2
Я б сказав, що делегат є контролером Qt, оскільки делегати отримують і надсилають вхід моделі, яка оновлює подання за допомогою сигналів.
Перерегінг-лк

82

Коротка відповідь

Qt MVC застосовується лише до однієї структури даних . Коли мова йде про MVC додатки ви не повинні думати про те QAbstractItemModelчи QListView.

Якщо ви хочете архітектуру MVC для всієї програми, Qt не має такої "величезної" моделі / структури перегляду. Але для кожного списку / дерева даних у вашій програмі ви можете використовувати підхід Qt MVC, який дійсно має контролер у своєму режимі перегляду. Дані всередині або поза моделлю; це залежить від того, який тип моделі ви використовуєте (власний підклас моделі: ймовірно, в межах моделі; наприклад, QSqlTableModel: зовні (але, можливо, кешований всередині моделі)). Для складання своїх моделей та поглядів використовуйте власні класи, які потім реалізують бізнес-логіку .


Довга відповідь

Модель / підхід Qt / підхід та термінологія:

Qt надає прості види для своїх моделей. У них вбудований контролер : вибір, редагування та переміщення елементів - це те, що в більшості випадків контролер «контролює». Тобто, інтерпретуючи введення користувача (клацання та переміщення миші) та надання відповідних команд моделі.

Моделі Qt - це справді моделі, що мають основні дані. Звичайно, абстрактні моделі не містять даних, оскільки Qt не знає, як їх зберігати. Але ви поширюєте QAb AbstractItemModel на свої потреби, додаючи свої контейнери даних до підкласу та роблячи модельний інтерфейс для доступу до ваших даних. Тож насправді, і я припускаю, що вам це не подобається, проблема полягає в тому, що вам потрібно запрограмувати модель, щоб отримати доступ до даних і змінити їх у структурі даних.

У термінології MVC модель містить і дані, і логіку . У Qt, ви вирішуєте, включите ви чи ні свою бізнес-логіку у свою модель чи поставите її поза, будучи "переглядом" самостійно. Навіть не зрозуміло, що означає логіка: вибір, перейменування та переміщення предметів? => вже реалізовано. Робите розрахунки з ними? => Поставте його зовні або всередині модельного підкласу. Зберігання або завантаження даних з / у файл? => Помістіть його всередині модельного підкласу.


Моя особиста думка:

Надати програмісту хорошу і загальну систему МВ (С) дуже важко . Оскільки в більшості випадків моделі прості (наприклад, лише списки рядків), Qt також забезпечує готовий до використання QStringListModel. Але якщо ваші дані складніші за рядки, то вирішувати, як ви хочете представити дані через інтерфейс моделі Qt / перегляду, залежати від вас. Якщо у вас є, наприклад, структура з 3 полями (скажімо, особами з ім'ям, віком і статтю), ви можете призначити 3 поля для 3 різних стовпців або 3 різних ролей. Мені не подобаються обидва підходи.

Я думаю, що модель / рамка перегляду Qt корисна лише тоді, коли потрібно відображати прості структури даних . Обробляти стає важко, якщо дані мають власні типи або структуровані не у дереві чи списку (наприклад, графік). У більшості випадків списків достатньо, і навіть в деяких випадках модель повинна містити лише один окремий запис. Особливо, якщо ви хочете моделювати один запис із різними атрибутами (один екземпляр одного класу), модель / перегляд Qt не є правильним способом відокремити логіку від користувальницького інтерфейсу.

Підводячи підсумок, я вважаю, що модель / рамка перегляду Qt є корисною лише тоді, коли ваші дані переглядаються одним із віджетів перегляду Qt . Це абсолютно марно, якщо ви збираєтеся написати власного переглядача для моделі, що містить лише один запис, наприклад, налаштування вашої програми або якщо ваші дані не мають типів для друку.


Як я використовував Qt model / view в (більшій) програмі?

Я колись написав (у команді) додаток, який використовує кілька моделей Qt для управління даними. Ми вирішили створити DataRoleдля зберігання фактичних даних, які були різного користувальницького типу для кожного підкласу моделі. Ми створили клас зовнішньої моделі під назвою, що Modelмістить усі різні моделі Qt. Ми також створили клас зовнішнього вигляду, який називається Viewпроведення вікон (віджетів), які підключені до моделей всередині Model. Таким чином, цей підхід є розширеним Qt MVC, адаптованим до наших власних потреб. І самі, Modelі Viewкласи не мають нічого спільного з Qt MVC.

Куди ми поставили логіку ? Ми створили класи, які робили фактичні обчислення даних, читаючи дані з вихідних моделей (коли вони змінювалися) та записуючи результати в цільові моделі. З точки зору Qt, ці класи логіки будуть переглядами, оскільки вони "підключаються" до моделей (не "перегляд" для користувача, а "вид" для бізнес-логічної частини програми).

Де контролери ? У оригінальній термінології MVC контролери інтерпретують введення користувача (миша та клавіатура) та дають команди моделі для виконання запитуваної дії. Оскільки представлення Qt вже інтерпретують введення користувачів, як перейменування та переміщення елементів, це не було потрібно. Але нам потрібна була інтерпретація взаємодії користувачів, яка виходить за рамки поглядів Qt.


Найбільше дратує те, що вам доведеться реалізувати абсолютно різні класи Qt Model залежно від обраного виду. Модель перегляду списку не буде належним чином підтримувати подання дерева та навпаки. Канонічна модель MVC може підтримувати безліч різних типів перегляду.
смерлін

3
@smerlin: Я не думаю, що це правильно. І QListView, і QTreeView вимагають лише інтерфейсу QAb абстрактItemView, тобто спеціальний підклас цього або конкретний клас на зразок QStandardItemModel повинен виконати цю вимогу для обох. Ви можете керувати деревом та перелічити одну модель.
jdi

1
@jdi: є випадки, коли ваші дані є і списком, і деревом ... наприклад, ви могли б хотіти відображати вашу файлову систему як дерево, або всі файли як список. Моделі Qts цього не дозволяють правильно. Впровадження QAb AbstractItemModel, що підтримує погляди дерев, дозволяє лише відображати всі файли / каталоги у вашій кореневій директорії як список, але ви не можете відображати всі файли як список. І не кажіть, що відображення даних дерев як списку не може бути корисним. Наприклад, ви можете, наприклад, легко сортувати їх, щоб знайти файл з найбільшим розміром файлів, якщо ви відображаєте свої файли у списку, дерева не дозволять цього.
смерлін

1
Тим не менше , проксі - модель ще що - то з вашої точки зору (оскільки вона змінює , як це дані розглядається ) і , таким чином , повинні належати до вашої думки. Якщо ви читаєте мою довгу відповідь: до Viewкласу "великий" слід додати проксі-модель, яка є базовою моделлю дерева та використовується переглядом списку вашої файлової системи. Як ви говорите: не повинно бути двох моделей для одних і тих же даних. Ніколи! (Але моделі проксі не враховуються як окремі моделі.)
leemes

1
@SamPinkus Це тому, що в цьому питанні немає чіткого " так" чи " ні" . Також існують різні реалізації QAbstractItemModel, деякі з яких є моделями у значенні MVC, а деякі - ні.
leemes

12

Термінологія не є правильною чи неправильною, вона корисна або марна.

Ви можете трохи змінити питання і запитати, чому Qt не є більш зручним для MVC. Відповідь на те, що перші розробники Qt вважають, що роз'єднання V від C в додатках GUI призводить до поганих Vs і Cs обох. Дизайн QWidget намагається спростити зв'язок взаємодії вводу миші з рішеннями про вихід пікселів, і ви можете зрозуміти, як це не дорога до MVC.


Я бачу вашу думку, і в основному я б запитав, чому Qt не є більш зручним для MVC, але це дуже важко зробити, коли термінологія MVC, що використовується в документації Qt, відрізняється від того, для чого MVC використовується зазвичай (як я пояснив у запитанні). І коли широко застосовується термінологія, і хтось використовує її зовсім інакше, ніж у решті світу, я схиляюся до думки, що це не тільки марно, але й просто невірно і заплутано (ця плутанина змусила мене задати питання в першу чергу місце). Мені буде дуже цікаво, якщо у вас є якісь посилання на ці речі, які десь обговорюються чи пояснюються. Спасибі
горн

Я нічого не можу сказати про те, чому документи Qt зараз говорять про MVC так, як вони це роблять. Я пішов з Trolltech давно, і мене спантеличують деякі речі, які були зроблені в документації з мого виходу. (Однак у своєму блозі я іноді трохи не
зважаю

Чи маєте ви уявлення про те, як узгоджено термінологію MVC у Qt. Чи використовувався він під час написання коду чи лише пізніше під час процесу документації.
gorn

Ми не використовували слово "MVC" в документації Qt під час мого часу в Trolltech. Взагалі я думаю, що найкраще документувати те, що там, а не писати про те, що там немає. Тим не менше, на Gitorious ви можете дізнатися, хто додав цей текст, і додайте цю особу безпосередньо.
arnt

1
Інший коментар. Ми обговорювали MVC під час проектування та ранньої фразової реалізації Qt (коли Trollech була компанією з трьох осіб), і ми оцінювали інструментарій GUI, який використовував MVC "належним чином", я не можу згадати його назву. Нашою думкою було те, що цей інструментарій було страшним у використанні, і що MVC була значною причиною цього.
arnt

3

Оскільки функція Model - відповідати на запити інформації, я думаю, що немає нічого поганого у визначенні таких методів як rowCount, columnCountі т. Д. Я думаю, що Model - це якась обгортка для джерела даних (незалежно від того, що це SQL-таблиця чи просто масив) , він надає дані в стандартній формі, і вам слід визначити методи залежно від структури джерела даних.


2

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

Я відчуваю, що плутанина виникає в їх класі QAbpositeModelItem. Цей клас не є модельним елементом, а скоріше, це інтерфейс до моделі. Щоб їх класи перегляду інтерфейсували з моделлю, їм довелося створити загальний абстрактний інтерфейс для моделі. Однак модель може бути одним елементом, списком елементів, таблицею з 2 і більше розмірами предметів тощо; тому їх інтерфейс повинен підтримувати всі ці варіанти моделей. Справді, це робить елементи моделей досить складними, а клей-код для того, щоб він працював з реальною моделлю, здається, трохи розтягує метафору.


Хоча я згоден з вами з класом QAbpositeModelItem, але я також думаю, що навіть без цього ускладнення їх MVC неправильно називають. Чи можете ви пояснити, чому ви вважаєте, що їх термінологія правильна. Мені б хотілося почути, чому я не прав у жодному з трьох своїх аргументів.
gorn

0

Я думаю, що ... Те, що вони називають Модель, насправді є лише контролером.

Ні, їх "модель" точно не є контролером.

Контролер - це частина видимих ​​користувачем елементів керування, які модифікують модель (і, отже, опосередковано змінюють подання). Наприклад, кнопка "видалити" є частиною контролера.

Я думаю, що часто виникає плутанина, оскільки багато хто бачить щось на кшталт "контролер модифікує модель" і вважають, що це означає мутуючі функції на їхній моделі, як метод "deleteRow ()". Але в класичному MVC контролер - це саме частина інтерфейсу користувача. Методи, що мутують модель, є просто частиною моделі.

З часу винайдення MVC його розрізнення між контролером і зором стає все більш напруженим. Подумайте над текстовим полем: він обидва показує вам якийсь текст і дозволяє редагувати його, так це перегляд чи контролер? Відповідь повинна бути, що вона є частиною обох. Ще коли ви працювали над телетайпом у 1960-х, відмінність була чіткішою - подумайте ed- але це не означає, що тоді для користувача все було краще!

Це правда, що їх QAbpositeItemModel є досить вищим рівнем, ніж зазвичай модель. Наприклад, елементи в ньому можуть мати колір фону (технічно пензлик), що є рішучим атрибутом перегляду! Отже, є аргумент, що QAbpositeItemModel більше схожий на вид, а ваші дані - модель. Правда полягає в тому, що він знаходиться десь між класичними значеннями погляду та моделі. Але я не бачу, як це контролер; якщо що-небудь, це віджет QT, який використовує його.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.