Как настроить 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. У вас есть несколько просмотров. У вас есть один вид для меню и пустой панели. Это представление создает другие необходимые представления, но не отображает их (visible = false), это представление также реализует интерфейс для каждого представления, которое оно содержит (т. Е. Дочерние представления), поэтому оно может быть доступно одному докладчику. Пустая панель заполнена другими видами ( Controls.Add(myview)) и ( (myview.visible = true). События, возникающие в этих «дочерних» представлениях, обрабатываются родительским представлением, которое, в свою очередь, передает событие докладчику, и наоборот, для передачи событий обратно дочерним элементам.

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

Раздел Е

Если у всех есть интерфейс, теперь основанный на том, как MVP сделан в вышеприведенных примерах, повлияет на этот ответ, поскольку они могут быть несовместимыми.

  1. У всего есть интерфейс, представление, презентатор и модель. Каждый из них, очевидно, имеет конкретную реализацию. Даже если у вас есть только один конкретный вид, модель и ведущий.

  2. Вид и Модель имеют интерфейс. Это позволяет взглядам и моделям отличаться. Презентатор создает / получает вид и моделирует объекты, и он просто служит для передачи сообщений между ними.

  3. Только вид имеет интерфейс. Модель имеет статические методы и не создается, поэтому нет необходимости в интерфейсе. Если вам нужна другая модель, докладчик вызывает другой набор статических методов класса. Будучи статичной, Модель не имеет ссылки на докладчика.

Личные мысли

Из всех различных вариантов, которые я представил (большинство я, вероятно, использовал в той или иной форме), которые, я уверен, есть и другие. Я предпочитаю A3, так как бизнес-логику можно использовать многократно за пределами MVP, B2 - для меньшего дублирования данных и меньшего количества инициируемых событий. C1, чтобы не добавлять в другой класс, конечно, он помещает небольшое количество логики, не поддающейся проверке, в представление (как визуализируется объект домена), но это может быть проверено кодом или просто просмотрено в приложении. Если бы логика была сложной, я бы согласился на класс адаптера, но не во всех случаях. Для раздела D я чувствую, что D1 создает представление, которое слишком велико по крайней мере для примера меню. Я использовал D2 и D3 раньше. Проблема с D2 заключается в том, что вам приходится писать много кода для маршрутизации событий от докладчика к правильному дочернему представлению, а он не совместим с перетаскиванием, каждому новому элементу управления требуется больше проводки для поддержки одного докладчика. D3 - мой предпочтительный выбор, но он добавляет еще больше классов в качестве докладчиков и моделей для работы с представлением, даже если представление оказывается очень простым или не нуждается в повторном использовании. Я думаю, что смесь D2 и D3 лучше всего зависит от обстоятельств. Что касается раздела E, я думаю, что все, что имеет интерфейс, может быть излишним, я уже делаю это для доменных / бизнес-объектов и часто не вижу в этом «никакого преимущества» в «дизайне», но это помогает при проверке объектов в тестах. Лично я бы видел E2 как классическое решение, хотя видел, как E3 использовался в 2 проектах, над которыми я работал ранее. Я думаю, что смесь D2 и D3 лучше всего зависит от обстоятельств. Что касается раздела E, я думаю, что все, что имеет интерфейс, может быть излишним, я уже делаю это для доменных / бизнес-объектов и часто не вижу в этом «никакого преимущества» в «дизайне», но это помогает при проверке объектов в тестах. Лично я бы видел E2 как классическое решение, хотя видел, как E3 использовался в 2 проектах, над которыми я работал ранее. Я думаю, что смесь D2 и D3 лучше всего зависит от обстоятельств. Что касается раздела E, я думаю, что все, что имеет интерфейс, может быть излишним, я уже делаю это для доменных / бизнес-объектов и часто не вижу в этом «никакого преимущества» в «дизайне», но это помогает при проверке объектов в тестах. Лично я бы видел E2 как классическое решение, хотя видел, как E3 использовался в 2 проектах, над которыми я работал ранее.

Вопрос

Я правильно внедряю MVP? Есть ли правильный способ сделать это?

Я читал работу Мартина Фаулера, в которой есть вариации, и я помню, когда я впервые начал заниматься MVC, я понял концепцию, но изначально не мог понять, где находится точка входа, у всего есть своя функция, но что контролирует и создает оригинал набор объектов MVC.

JonWillis
источник
2
Причина, по которой я задаю этот вопрос, заключается в том, что я пытаюсь понять его практически с первой попытки. Я предпочел бы придерживаться стандартного MVP, а не создавать 6 приложений, использующих разные варианты для одного и того же шаблона.
ДжонВиллис
Идеально ... Я давно хотел спросить об этом
Король

Ответы:

4

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

Для меня, я чувствую, что ведущий почти всегда должен быть отправной точкой. Наличие пользовательского интерфейса в качестве точки входа создает слишком много логики в пользовательском интерфейсе и лишает его возможности заменять новый пользовательский интерфейс без больших изменений в коде. И действительно, это работа докладчика.

Вальтер
источник
Может быть, вопрос, который я должен задать, это любой из способов использовать MVP просто неправильно. Я согласен с вариациями, подходящими для разных сценариев, но считаю, что должен быть общепринятый подход. Примеры MVP - это простые примеры, и почти все с одинаковой потребностью редактировать объект домена и сохранять изменения. Тем не менее, из этих примеров с той же целью были получены вышеуказанные варианты. Я только что закодировал часть приложения, используя события, запускаемые в представлении, для обработки в докладчике, но я мог бы иметь представление, содержащее ссылку на докладчика и непосредственно вызывать методы.
ДжонВиллис,
Я согласен со всеми усилиями, направленными на упрощение представления, чтобы оправдать, что он не тестируется модулем, тогда докладчик должен иметь контроль. Единственное, что меня беспокоит в этом (я думаю, что я могу ошибаться), это то, что, скажем, winforms / usercontrols, возможно, нужно будет связать с родительскими элементами, и подумать, нужна ли дополнительная логика в докладчике, чтобы написать это.
ДжонВиллис
@Jon - Пути MVP не так? В моей книге это будет, когда мнение узнает о ведущем. Это не может быть «неправильно» в том смысле, что это работает, но это не будет MVP, оно превращается в нечто другое. Проблема с шаблонами проектирования заключается в том, что примеры всегда максимально чисты и просты. Затем, когда вы впервые приступаете к их реализации, реальный мир вскочил и сказал: «Эй, настоящие приложения намного сложнее, чем этот ничтожный пример». Вот где начинается ваш рост. Найдите то, что работает для вас и обстоятельств приложения.
Уолтер
Спасибо за совет. Я помню обучение MVC в университете. Звучит великолепно, но с чистым холстом вы задаетесь вопросом, с чего начать и как это действительно работает. С точки зрения того, что MVP ошибочен, я имею в виду, что любые идеи / варианты MVC, которые я опубликовал выше, были неверны, то есть когда представление знает, как работает докладчик. Или представление должно иметь ссылку на интерфейс презентатора или конкретного типа и т. Д. Просто много разных вариантов, которые могут работать для одной и той же цели.
ДжонВиллис
1
@Jon - Ваши вариации в значительной степени соответствуют духу MVP. Что касается работы с интерфейсами или конкретными типами, это будет зависеть от обстоятельств приложения. Если приложение довольно маленькое, не очень сложное, возможно, добавление интерфейсов не требуется. Мне нравится делать вещи максимально простыми, пока не станет ясно, что приложению абсолютно необходимо реализовать архитектуру X. См. Этот ответ для более подробной информации: programmers.stackexchange.com/questions/34547/…
Уолтер,
4

Мы используем модифицированную форму MVP в нашем приложении .NET 2.0 Winforms. Нам не хватало двух частей: модифицированного адаптера WPF ViewModel и добавления привязки данных. Наш специфический образец - MVPVM.

Мы подключаемся в качестве первого докладчика почти во всех случаях, за исключением пользовательских пользовательских элементов управления, которые подключены в виде первого для удобства дизайнеров. Мы используем внедрение зависимостей, генерируемые кодом ViewModels, BDD для докладчиков и TDD / TED для модели.

Виртуальные машины - это просто массивный плоский набор свойств, которые вызывают PropertyChanged при их изменении. Было очень легко сгенерировать их с помощью кода (и связанных с ними тренировочных юнит-тестов). Мы используем их для чтения и записи в интерактивные элементы управления, а также для управления включенными состояниями. ViewModel связан с View, так как мы используем привязку данных почти все остальное.

Иногда в представлении будут методы для выполнения задач, которые виртуальная машина не может выполнить. Это обычно контролирует видимость элементов (WinForms может быть требователен) и вещи, которые отказываются быть привязанными к данным. Представление всегда предоставляет такие события, как «Логин» или «Перезапуск», с соответствующими EventArgs, чтобы воздействовать на поведение пользователя. Если нам не пришлось использовать хак, такой как «View.ShowLoginBox», представление полностью взаимозаменяемо, если оно соответствует общим требованиям дизайна.

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

Брайан Бетчер
источник
Я знаю, что ваш MVPVM может представлять коммерческий интерес, но если все в порядке, не могли бы вы предоставить пример кода? На боковой заметке, где вы рисуете линию на то, что делает в модели и что идет в презентере. Я видел, что докладчик настолько прост, что он обрабатывает события представления и просто вызывает модель, чтобы докладчик получал доступ к слоям данных для передачи бизнес-объектов в модель, вплоть до замены модели презентатором.
ДжонВиллис
Да, позвольте мне закончить пример. Он будет немного адаптирован к нашему бизнесу, поскольку я использую его в качестве внутреннего учебного пособия.
Брайан Бетчер
Спасибо, я посмотрю это на выходных, чтобы увидеть, понимаю ли я это
JonWillis
@insta - ссылка не работает, не могли бы вы загрузить ее куда-нибудь?
Ив Шелпе
1
Дерьмо я просто удалил его, как неделю назад. Цифры :(
Брайан Бетчер
2

Я использую версию PureMvc, которая была модифицирована для .Net, а затем расширена мной.

Я привык к использованию PureMvc в приложениях Flex. Это базовый тип фреймворка, поэтому его довольно легко адаптировать, если вы хотите настроить его.

Я взял следующие вольности с этим:

  • Используя рефлексию, я смог получить приватные свойства в view-mediator, чтобы перейти в класс формы и получить (приватную) ссылку на каждый элемент управления, который я передавал.
  • Используя отражение, я могу автоматически связать элементы управления с сигнатурами событий в моем посреднике, которые являются общими, поэтому я просто включаю параметр отправителя.
  • Обычно PureMvc хочет, чтобы производные посредники определяли свои интересы уведомления в функции, которая будет возвращать массив строк. Поскольку мои интересы в основном статичны, и я хотел иметь более простой способ увидеть интересы посредников, я сделал модификацию, чтобы посредник также мог объявить свои интересы с помощью набора переменных-членов с определенной подписью: _ _ _ <classname> _ <имя-уведомления>. Таким образом, я могу видеть, что происходит, используя дерево элементов IDE вместо того, чтобы заглядывать внутрь функции.

В PureMvc вы можете использовать команду в качестве точки входа, типичная команда Start настроит модель в максимально возможной степени, затем создаст MainForm, создаст и зарегистрирует посредник для этой формы и с этой формой, а затем сделает Application.Run. на форме.

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

Система, которую я использую, совместима с перетаскиванием, если я понимаю ваше значение. Фактическая форма все создается в VS, но мой опыт только с формами, которые имеют статически созданные элементы управления. Такие вещи, как динамически создаваемые пункты меню, кажутся выполнимыми с небольшой настройкой посредника для этого меню или подменю. Это может стать проблемой, когда посредник не имеет статического корневого элемента, к которому можно подключиться, и вы попадаете в создание динамических посредников «экземпляра».

отметка
источник