Думки щодо впровадження Model-View-Presenter


34

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

Я дивився на Model-View-Presenter, але не знаю, як саме реалізувати його. Наприклад, мій погляд має кілька діалогових вікон.

  • Чи повинен бути клас Перегляд із екземплярами кожного із діалогів? Тоді в такому випадку, як діалоги повинні взаємодіяти з ведучим? тобто. якщо в окремому діалоговому вікні потрібно запитувати дані від Моделі через презентатор, то як діалогове вікно має посилатися на презентатора? Через посилання на представлений йому вид під час будівництва?
  • Я думав, може, погляд повинен бути статичним класом? Потім діалогові вікна GetView та отримання презентації звідти ...
  • Я думав над тим, щоб налаштувати презентацію з правом власності на Вид і модель (на відміну від представлення, у якого презентатор і презентатор має модель) і презентатор, який реєструє зворотні виклики для подій у Перегляді, але це робить його здається багато більше пов'язане (або залежно від мови, принаймні.)

Я намагаюся:

  1. зробіть це максимально відокремленим
  2. в ідеалі дозволяють поєднати презентатор / модель з видами інших мов (я не робив тонну міжмовних речей, але я знаю, що це можливо, особливо більше, ніж void(void)я можу дотримуватися принаймні додаток C # із Бібліотека C ++ ...
  3. зберігати код чистим та простим

Отже .. будь-які пропозиції, як взаємодіяти?


Ви подивилися цю статтю?: En.wikipedia.org/wiki/Model-view-presenter
Бернар

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

Відповіді:


37

Ласкаво просимо на слизький схил. Ви до цього моменту зрозуміли, що існує нескінченна зміна всіх взаємодій із переглядом моделі. MVC, MVP (Taligent, Dolphin, Pasive View), MVVM лише для назви.

Модель Presenter Presenter Model, як і більшість архітектурних моделей, відкрита для різноманітності та експериментів. Єдине, що має всі спільні варіанти - це роль ведучого як "посередника" між поглядом та моделлю. Два найпоширеніших - це пасивний вигляд та контролюючий ведучий / контролер - [ фоулер ]. Passive View розглядає інтерфейс користувача як дуже неглибокий інтерфейс між користувачем та ведучим. Він містить дуже мало, за будь-якої логіки, делегуючи стільки відповідальності перед ведучим. Нагляд за ведучим / контролеромнамагається скористатися прив'язкою даних, вбудованою у безліч фреймворків інтерфейсу. Користувальницький інтерфейс обробляє синхронізацію даних, але подає презентатор / контролер для більш складної логіки. В будь-якому випадку модель, перегляд та презентатор утворюють тріаду

Існує багато способів зробити це. Дуже звичайно бачити цю обробку, розглядаючи кожен діалог / форму як інший погляд. Багато разів між переглядами та ведучими існує взаємозв'язок 1: 1. Це не важке, швидке правило. Досить поширеним є те, що один ведучий обробляє декілька пов'язаних поглядів або навпаки. Все залежить від складності погляду та складності бізнес-логіки.

Щодо того, як перегляди та презентатори отримують посилання один на одного, це іноді називають проводкою . У вас є три варіанти:

Перегляд містить посилання на презентатора
Форма або діалогове вікно реалізує подання. У формі є обробники подій, які делегують до презентатора, використовуючи прямі виклики функцій:

MyForm.SomeEvent(Sender)
{
  Presenter.DoSomething(Sender.Data);
}

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

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

Presenter.SomeEvent(Sender)
{
  DomainObject.DoSomething(View.SomeProperty);
  View.SomeOtherProperty = DomainObject.SomeData;
}

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

View.SomeEvent(Sender)
{
  Presenter.DoSomething();
}

Presenter.DoSomething()
{
  View.SomeProperty = DomainObject.Calc(View.SomeProperty);
}

Є інші питання, які слід враховувати з моделями MVP. Порядок створення, час роботи об'єкта, де відбувається електропроводка, спілкування між тріадами MVP, але ця відповідь виросла досить довго.


1
Це, безумовно, корисно. Комунікація між тріадами та життям - це те, коли я зараз відчуваю проблеми, коли я розумію щось із цього.
пробір

8

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

Тримайте їх відокремленими. Перегляд повинен реалізовувати інтерфейс, який формує зв'язок між видом і ведучим. Представлення створює ведучого і вводить себе в презентатора та розкриває методи, які він пропонує для ведучого взаємодіяти з поданням. Подання несе відповідальність за впровадження цих методів або властивостей будь-яким способом. Зазвичай у вас є одна думка: один ведучий, але в деяких випадках у вас може бути багато переглядів: один ведучий (web, wpf тощо). Ключовим тут є те, що ведучий нічого не знає про реалізацію інтерфейсу та взаємодіє з представленням лише через інтерфейс.

Ось приклад. Спочатку у нас є клас перегляду з простим методом відображення повідомлення користувачеві:

interface IView
{
  public void InformUser(string message);
}

Тепер ось ведучий. Зауважте, що презентатор приймає IView у свій конструктор.

class Presenter
{
  private IView _view;
  public Presenter(IView view)
  {
    _view = view;
  }
}

Тепер ось власний інтерфейс користувача. Це може бути вікно, діалог, веб-сторінка тощо. Не має значення. Зауважте, що конструктор подання створить презентатора, ввівши його в нього.

class View : IView
{
  private Presenter _presenter;

  public View()
  {
    _presenter = new Presenter(this);
  }

  public void InformUser(string message)
  {
    MessageBox.Show(message);
  }
}

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

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

class Presenter
{
  public void DoSomething()
  {
    _view.InformUser("Starting model processing...");
  }
}

Тут ви отримуєте свою розв'язку. Ведучий містить лише посилання на реалізацію IView і не дуже цікавий, як він реалізований.

Це також погана реалізація mans, оскільки ви маєте посилання на Presenter у поданні, а об'єкти встановлюються за допомогою конструкторів. У більш надійному рішенні ви, можливо, хочете поглянути на інверсію керуючих (IoC) контейнерів, таких як Windsor, Ninject тощо, які дозволять вирішити впровадження IView для вас під час виконання на вимогу і тим самим зробити його ще більш відокремленим.


4

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

Основна суть Контролера полягає в тому, що якщо ви внесете зміни в Вигляд, то модель не повинна змінюватися, і навпаки (якщо модель змінює модель, перегляд не повинен), тому що контролер - це те, що перекладає Повторне моделювання у вигляд і назад. Але Контролер зміниться, коли зміни або Модель, або Перегляд будуть зроблені, тому що ви фактично повинні перевести в Контролер, як модель переглядається, як повернути зміни, внесені в Перегляд назад, в режим.

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

Однак, вам потрібно мати посилання між різними компонентами, щоб все це працювало. Контролеру потрібно знати про Перегляд для передачі даних, Перегляд повинен знати про Контролер, щоб повідомити про нього, коли було внесено зміни (наприклад, коли Користувач натискає "Зберегти" або "Нове ..."). Контролер повинен знати про Модель для отримання даних, але я б стверджував, що Модель не повинна знати про інше.

Caveat: Я походжу з абсолютно Mac, Objective-C, какао-фону, який насправді підштовхує вас до парадигми MVC, хочете ви цього чи ні.


Це, безумовно, моя мета. Моя основна проблема полягає в тому, як налаштувати представлення даних - чи повинен це бути клас із екземпляром кожного діалогового вікна, а потім використовувати View.Getters, які викликають Dialog.Getters, або якщо презентатор повинен мати можливість викликати Dialog.Getters безпосередньо ( це здається занадто щільно поєднаним, так що, мабуть, ні?)
trycatch

Я думаю, що ведучий / контролер повинен нести повну відповідальність за погляди, тому останні. Знову ж таки, певна муфта повинна відбутися, але принаймні, якщо напрямок відповідальності чіткий, то у довгостроковій перспективі обслуговування повинно бути простішим.
Філіп Реган

2
Я, безумовно, погоджуюся, що P / C повинен відповідати за Перегляд, але я подумав, що частиною того, що повинно було зробити MVP потужним, є можливість витягнути всю бібліотеку інтерфейсу та підключити нову в і з деяким масажуванням (dllimporting та багато чого іншого) мати можливість запустити ще один на своєму місці. Чи не буде це складніше, коли контролер / ведучий отримує прямий доступ до діалогів? Я, звичайно, не намагаюся сперечатися, просто далі розумію :)
trycatch

Я думаю, що реальна потужність виходить з двох напрямків: перший полягає в тому, що View і Model не мають нічого спільного з іншими, а другий, що більшість розробників, двигун програми, робиться акуратно блок, контролер. Але певна кровотеча відповідальності неодмінно відбудеться. Принаймні більшість замін інтерфейсів буде здійснюватися в Контролері, і будь-яке посилання з представлення буде мінімальним. Як говорили інші, очікується і дозволяється деяка кровотеча логіки. MVC - не чарівна куля.
Філіп Реган

Важливим моментом для роз'єднання є те, що презентатор ТОЛЬКО отримує доступ до перегляду через чітко визначені інтерфейси (бібліотека інтерфейсу користувача незалежна), так що бібліотека UI може бути замінена на іншу (іншу, яка реалізує той самий інтерфейс для форми / вікна / діалогу / сторінки / контроль / що завгодно)
Марсель Тот

2

Загалом, ви хочете, щоб ваша модель охоплювала всі взаємодії з цією моделлю. Наприклад, ваші дії CRUD (Створення, читання, оновлення, видалення) є частиною моделі. Те саме стосується спеціальних розрахунків. Для цього є кілька вагомих причин:

  • Простіше автоматизувати тестування цього коду
  • Він зберігає всі ті важливі речі в одному місці

У вашому контролері (додаток MVC) все, що ви робите, - це збирання моделей, які потрібно використовувати у вашому представленні, та виклик відповідних функцій моделі. Будь-які зміни стану моделі відбуваються в цьому шарі.

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

Складання загального принципу на фактичні класи

Пам'ятайте, що ваші діалоги - це перегляди. Якщо у вас вже є діалоговий клас, немає підстав для створення іншого класу "Перегляд". Шар Presenter по суті пов'язує модель з елементами управління у Перегляді. Ділова логіка та всі важливі дані зберігаються у моделі.

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