Як встановити MVP для рішення Winforms?


14

У минулому я використовував MVP і MVC, і я віддаю перевагу MVP, оскільки він набагато краще контролює потік виконання.

Я створив свою інфраструктуру (класи сховища / сховища) і без проблем використовую їх при жорсткому кодуванні зразкових даних, тому зараз я переходжу на графічний інтерфейс і готую свій MVP.

Розділ А

  1. Я бачив MVP, використовуючи подання як точку входу, тобто в методі конструктора подань він створює презентатор, який, у свою чергу, створює модель, з'єднуючи події за потребою.

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

  3. Як і в 2, але модель не передається ведучому. Натомість модель - це статичний клас, де викликуються методи і відповіді повертаються безпосередньо.

Розділ В

З точки зору збереження подання та моделі в синхронізації я бачив.

  1. Щоразу, коли значення в представленні змінюється, тобто TextChangedподія в .Net / C #. Це запускає а, DataChangedEventщо передається в модель, щоб постійно тримати її синхронізованою. І коли модель змінюється, тобто фонова подія, яку вона слухає, то подання оновлюється за допомогою тієї самої ідеї підняття а DataChangedEvent. Коли користувач хоче здійснити зміни, SaveEventвін запускається, переходячи в модель, щоб зробити збереження. У цьому випадку модель імітує дані подання та обробляє дії.

  2. Подібно до # b1, проте представлення не синхронізується з моделлю весь час. Натомість, коли користувач хоче внести зміни, SaveEventйого звільняють, а ведучий захоплює останні деталі та передає їх у модель. в цьому випадку модель не знає про дані переглядів, поки не буде потрібно діяти на них, і в цьому випадку передаються всі необхідні деталі.

Розділ С

Відображення бізнес-об'єктів у поданні, тобто об'єкт (MyClass), не примітивні дані (int, double)

  1. У поданні є поля властивостей для всіх його даних, які відображатимуться як об’єкти домену / бізнесу. Наприклад, view.Animalsвиставляє IEnumerable<IAnimal>властивість, навіть якщо представлення переробляє їх у "Вузли" в TreeView. Тоді для вибраної тварини це було б викрито SelectedAnimalяк IAnimalвластивість.

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

Розділ D

Кілька представлень, використовуваних для створення єдиного елемента керування. тобто у вас складний вигляд із простою моделлю, як збереження об'єктів різних типів. У вас може бути система меню поруч із кожним клацанням на пункт, показані відповідні елементи керування.

  1. Ви створюєте величезний вигляд, який містить усі окремі елементи керування, які відкриваються через інтерфейс перегляду.

  2. У вас кілька переглядів. У вас є один вид меню та пуста панель. Цей подання створює інші необхідні представлення даних, але не відображає їх (видимі = хибні); цей погляд також реалізує інтерфейс для кожного перегляду, який він містить (тобто дочірні подання), щоб він міг виставляти одного ведучого. Порожню панель заповнено іншими видами ( Controls.Add(myview)) та ( (myview.visible = true). Події, підняті в цих "дочірніх" оглядах, обробляються батьківським видом, який, в свою чергу, передає подію ведучому, і навпаки для подачі подій назад до дочірніх елементів.

  3. Кожен погляд, будь то основний батьківський або менший дочірній погляд, кожен з них має провідний власний ведучий та модель. Ви можете буквально просто перенести елемент управління переглядом у існуючу форму, і він буде готовий до функціональності, просто потрібно підключення до ведучого за кадром.

Розділ Е

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

  1. Все має інтерфейс, вид, презентатор та модель. Кожен із них тоді, очевидно, має конкретну реалізацію. Навіть якщо у вас є лише один конкретний вид, модель та ведучий.

  2. У View і Model є інтерфейс. Це дозволяє відрізнятися поглядам та моделям. Ведучий створює / надає об'єкти перегляду та моделювання, і він просто служить для передачі повідомлень між ними.

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

Особисті думки

З усіх різних варіацій, які я представив (більшість я, мабуть, використовував у якійсь формі), яких я впевнений, що їх більше. Я вважаю за краще A3 підтримувати багаторазову використання бізнес-логіки за межами MVP, B2 для меншої кількості дублювання даних та зменшення подій. C1 для не додавання до іншого класу, переконайтеся, що він додає невелику кількість логіки, що не перевіряється одиницею, у вигляд (як візуалізується об’єкт домену), але це може бути переглянуто код або просто переглянуто в додатку. Якби логіка була складною, я погодився б на клас адаптерів, але не у всіх випадках. Для розділу D я вважаю, що D1 створює занадто великий вид для прикладу меню. Я раніше використовував D2 і D3. Проблема з D2 полягає в тому, що вам доводиться писати багато коду для маршрутизації подій до та від ведучого до правильного дочірнього подання, а його сумісність не перетягування / падіння, кожен новий елемент управління потребує більше проводки для підтримки єдиного ведучого. D3 - це мій переважний вибір, але він додає ще більшу кількість класів у якості ведучих та моделей для вирішення погляду, навіть якщо подання виглядає дуже простим або не потребує повторного використання. Я думаю, що суміш D2 і D3 найкраще грунтується на обставинах. Що стосується розділу E, я думаю, що все, що має інтерфейс, може бути надмірним, я вже це роблю для об’єктів домену / бізнесу і часто не бачу переваги в "дизайні", роблячи це, але це допомагає в глузуванні з об'єктів у тестах. Особисто я бачив би Е2 як класичне рішення, хоча бачив Е3, який використовувався у двох проектах, над якими я працював раніше. Я думаю, що суміш D2 і D3 найкраще грунтується на обставинах. Що стосується розділу E, я думаю, що все, що має інтерфейс, може бути надмірним, я вже це роблю для об’єктів домену / бізнесу і часто не бачу переваги в "дизайні", роблячи це, але це допомагає в глузуванні з об'єктів у тестах. Особисто я бачив би Е2 як класичне рішення, хоча бачив Е3, який використовувався у двох проектах, над якими я працював раніше. Я думаю, що суміш D2 і D3 найкраще грунтується на обставинах. Що стосується розділу E, я думаю, що все, що має інтерфейс, може бути надмірним, я вже це роблю для об’єктів домену / бізнесу і часто не бачу переваги в "дизайні", роблячи це, але це допомагає в глузуванні з об'єктів у тестах. Особисто я бачив би Е2 як класичне рішення, хоча бачив Е3, який використовувався у двох проектах, над якими я працював раніше.

Питання

Чи правильно я реалізую MVP? Чи є правильний шлях про це?

Я читав твір Мартіна Фаулера, який має різні варіанти, і пам’ятаю, коли я вперше почав робити MVC, я зрозумів цю концепцію, але не міг спочатку розібратися, де точка входу, все має свою функцію, але що контролює і створює оригінал набір об’єктів MVC.


2
Причиною задавати це питання є те, що я прагну виправити це майже з першої спроби. Я вважаю за краще мати стандартний MVP, який слід дотримуватися, а не створювати 6 додатків, використовуючи різні варіанти для одного шаблону.
JonWillis

Ідеально ... Я хотів це давно запитати
Король

Відповіді:


4

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

Для мене я вважаю, що ведучий майже завжди повинен бути точкою входу. Наявність інтерфейсу користувача в якості точки введення вкладає занадто багато логіки в інтерфейс користувача і забирає можливість заміни нового інтерфейсу без великих змін кодування. І справді це ОСОБА робота ведучого.


Можливо, питання, яке я повинен задати, - це будь-який із способів використання MVP просто невірно. Я погоджуюся з варіантами, що відповідають різним сценаріям, але вважаю, що має бути загальновизнаний підхід. Приклади MVP - це прості приклади і майже всі з однаковою потребою - редагувати об’єкт домену та зберігати зміни. Однак із цих прикладів з тією ж метою були описані вищезазначені варіанти. Я щойно зашифрував частину програми, використовуючи події, запущені у поданні, щоб обробляти презентатора, але я міг би переконати, що вона має посилання на презентатора і безпосередньо методи виклику.
JonWillis

Я погоджуюся з усіма зусиллями, спрямовані на спрощення подання, щоб виправдати, що це не тестування одиниці, то ведучий повинен мати контроль. Моя єдина проблема з цим (я думаю, що в моїй голові так може бути неправильним) полягає в тому, що скажімо, що winforms / usercontrols можуть бути пов’язані з батьківськими елементами і задаються питанням, чи потрібна додаткова логіка для ведучого, щоб написати це.
JonWillis

@Jon - Шляхи MVP помиляються? У моїй книзі це було б тоді, коли думка знає про ведучого. Це не може бути "неправильним" у тому сенсі, що це працює, але це просто не було б MVP, воно перетворилося на щось інше на той момент. Проблема моделей дизайну полягає в тому, що приклади завжди максимально чисті та прості. Тоді, коли ви вперше реалізовуєте їх, і реальний світ підскакує і каже: "Ей реальні додатки набагато складніші, ніж цей хижий приклад". Ось звідки починається ваше зростання. Дізнайтеся, що працює для вас та обставин програми.
Вальтер

Дякую за пораду. Я пам’ятаю, як навчався на МВЦ в університеті. Чудово звучало, але з порожнім полотном ви задаєтеся питанням з чого почати і як це насправді працює. З точки зору того, що MVP помиляється, я маю на увазі, чи були будь-які ідеї / варіоти MVC, які я розміщував вище неправильного способу цього, тобто коли представлення знає, як працює ведуча. Або вигляд повинен мати посилання на інтерфейс ведучого або конкретного типу тощо. Просто багато різних варіацій, які можуть працювати з однією і тією ж метою.
JonWillis

1
@Jon - Ваші варіанти в значній мірі відповідають духу MVP. Що стосується роботи з інтерфейсами чи конкретними типами, це залежатиме від обставин програми. Якщо додаток досить невеликий, не дуже складний, можливо, додавати інтерфейси не потрібно. Мені подобається зберігати речі максимально просто, поки не стане зрозуміло, що додатку абсолютно потрібно реалізувати архітектуру X. Дивіться цю відповідь для більш детальної інформації: programmers.stackexchange.com/questions/34547/…
Walter

4

Ми використовуємо модифіковану форму MVP у нашому додатку .NET 2.0 Winforms. Дві частини, які нам бракували, були модифікованим адаптером WPF ViewModel і додавали прив'язку даних. Наша конкретна модель - MVPVM.

Ми виступаємо в ролі ведучого майже в кожному випадку, за винятком користувацьких контролів користувачів, які проводяться з точки зору передусім для зручності дизайнера. Ми використовуємо введення залежності, ViewModels, що генерується кодом, BDD для презентаторів та TDD / TED для моделі.

ВМ - це просто масивний, рівний набір властивостей, які піднімають PropertyChanged, коли вони змінюються. Генерувати їх було за допомогою коду (та пов'язаних з ними тестів на виконання одиниць). Ми використовуємо їх для читання та запису до керованих користувачем елементів керування та контролю активованих статусів. ViewModel поєднаний з представленням, оскільки ми використовуємо прив'язку даних для чортового поблизу всього іншого.

У представленні час від часу є методи, які дозволять досягти речей, які VM не може. Зазвичай це контроль видимості елементів (WinForms може бути вибагливим щодо цього) та речей, які відмовляються бути пов'язаними з даними. Перегляд завжди розкриває такі події, як "Увійти" або "Перезапустити", з відповідними EventArgs, щоб діяти на поведінку користувачів. Якщо нам не довелося використовувати хак на кшталт "View.ShowLoginBox", View повністю взаємозамінний, якщо він відповідає загальним дизайнерським вимогам.

На це нам знадобилося приблизно 6-8 місяців, щоб зменшити цю схему. Він має багато штук, але дуже гнучкий і надзвичайно потужний. Наша конкретна реалізація дуже асинхронна та орієнтована на події, що може бути лише артефактом інших вимог, а не побічним ефектом дизайнерської поведінки. Наприклад, я додав синхронізацію потоків до базового класу, від якого наслідується наш VM (який просто викрив метод OnPropertyChanged, щоб підняти подію) - та poof, тепер ми можемо мати багатопотокові презентації та моделі.


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

Так, дозвольте закінчити приклад. Він буде трохи адаптований до нашого бізнесу, оскільки я використовую його як внутрішній інструмент навчання.
Брайан Боттчер

Дякую, я перегляну його на вихідних, щоб побачити, чи я це розумію
JonWillis

@insta - посилання не працює, ви можете її десь перезавантажити?
Ів Шельпе

1
Лайно я щойно видалив його, як тиждень тому. Цифри :(
Брайан Ботчер

2

Я використовую версію PureMvc, модифіковану для .Net, а потім розширену власноруч.

Я звик до PureMvc від його використання у програмах Flex. Це каркас з голими кістками, тому його досить легко адаптувати, якщо ви хочете його налаштувати.

Я взяв із собою такі свободи:

  • Використовуючи рефлексію, я зміг отримати приватні властивості у представника-посередника, щоб вийти до класу форм і захопити (приватне) посилання на кожен елемент управління, який я опосередковував.
  • Використовуючи відображення, я можу автоматично підключити елементи керування до підписів подій у моєму посереднику, які є загальними, тому я просто вмикаю параметр відправника.
  • Зазвичай PureMvc хоче, щоб похідні посередники визначали свої інтереси сповіщення у функції, яка повертає масив рядків. Оскільки мої інтереси здебільшого статичні, і я хотів легше зрозуміти інтереси посередників, я здійснив модифікацію, щоб медіатор також міг заявити про свої інтереси за допомогою набору змінних членів із певним підписом: _ _ _ <classname> _ <ім'я повідомлення> Таким чином я бачу, що відбувається за допомогою дерева-члена IDE, а не заглядати всередину функції.

У PureMvc ви можете використовувати Command як точку входу, типова команда Start встановлює Модель настільки, наскільки це можливо, потім створює MainForm, створює та реєструє посередника для та з цією формою, після чого виконайте Application.Run за формою.

Посередник за формою буде відповідальним за налаштування всіх субмедіаторів, деякі з них можна автоматизувати, знову ж таки, використовуючи прийоми рефлексії.

Система, якою я користуюся, сумісна з перетягуванням і перетягуванням, якщо я розумію ваше значення. Фактична форма створена у VS, але мій досвід лише у формах, які мають статично створені елементи управління. Такі речі, як динамічно створені пункти меню, здаються здійсненними, якщо трохи змінити посередник для цього меню чи підменю. Де б це було волохатим - це тоді, коли у посередника не було статичного кореневого елемента, на який можна було б підключитись, і ви почали створювати динамічні посередники "екземпляра".

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