Я разработчик C ++, который с тех пор использует шаблон MVC для разработки GUI.
Недавно я хотел вернуться в C # и настроить приложение Windows Forms, но теперь я немного растерялся, как перенести его в MVC-совместимую структуру.
В настоящее время я пытаюсь «объявить» класс, который мне дан для WinForms в качестве представления, и добавить класс для модели и контроллера в фоновом режиме. Тем не менее, я не совсем уверен, как взаимодействовать с событиями, такими как нажатие кнопки. Обычно я перенаправляю эти события на контроллер и выполняю действия в представлении после завершения.
Это кажется довольно неудовлетворительным в этом созвездии. Например, если бы я хотел реализовать кнопку «Выход», мне пришлось бы перенаправить событие из представления в контроллер, а также реализовать дополнительный открытый метод в моем представлении, который затем можно вызывать из контроллера, пока я может просто вызвать Close () из View в первом случае.
У вас есть какой-нибудь совет для меня? Мое понимание Windows Forms в C # просто недостаточно хорошо, чтобы попробовать реализацию MVC? Я даю классу форм неправильную роль? Является ли MVC просто неподходящей архитектурой для этого варианта использования?
Ответы:
По совпадению, я работаю над проектом WinForms, который создан по образцу MVC. Я бы не назвал это идеальным ответом, но я объясню мой общий дизайн, и, надеюсь, это поможет вам придумать свой собственный.
Судя по чтению, которое я сделал перед началом этого проекта, кажется, что нет «правильного» способа реализовать это. Я следовал простым принципам разработки ООП и MVC, а остальное было методом проб и ошибок при разработке рабочего процесса.
Нет ..? В вашем вопросе недостаточно контекста, чтобы дать прямой ответ на этот вопрос. Почему вы используете MVC в первую очередь? Каковы нефункциональные требования вашего проекта? Ваш проект будет очень тяжелым для пользовательского интерфейса? Вы больше заботитесь о безопасности и предпочитаете многоуровневую архитектуру? Каковы основные компоненты вашего проекта? Возможно, каждому компоненту нужен свой шаблон проектирования. Узнайте, почему вы хотите использовать этот шаблон проектирования в первую очередь, и вы можете ответить на свой вопрос;)
Моя причина использования MVC: по моему мнению, это довольно простой шаблон проектирования, и мой дизайн в значительной степени основан на взаимодействии с пользователем. Способ, которым MVC позволяет разработчику разделять проблемы, достаточен и для моего приложения. Это делает мой код много более ремонтопригодны и проверяемым.
Я также предполагаю, что я использую больше гибридного дизайна. Как правило, идеальная концепция, представленная в программной инженерии, фактически не реализуется на практике. Вы можете изменить дизайн в соответствии с потребностями вашего проекта. Не нужно увлекаться тем, что правильно или неправильно. Существуют общие практики, но правила всегда можно согнуть или нарушить, если вы не стреляете себе в ногу.
Моя реализация началась с разработки высокого уровня, которая дала мне представление о том, какие компоненты мне понадобятся. Лучше всего начать с этого и продолжить свой путь в архитектуре. Вот схема пакета для проекта (созданного в StarUML):
Обратите внимание, что каждый отдельный уровень, кроме уровня представления, зависит от системы обмена сообщениями. Это общий «язык», который нижние уровни и подсистемы этих уровней используют для общения друг с другом. В моем случае это было простое перечисление, основанное на операциях, которые можно выполнить. Что подводит меня к следующему пункту ...
Думайте об операциях или командах как об основании вашей реализации. Что вы хотите, чтобы ваше приложение делало? Разбейте его на самые основные операции. Например: CreateProject, WriteNotes, SaveProject, LoadProject и т. Д. В GUI (или классах форм) произойдет какое-то событие (например, нажатие кнопки). С каждой операцией связан метод контроллера. В этом случае что-то вроде выхода слишком просто. Приложение может быть просто закрыто из класса Form. Но предположим, что я сначала хотел сохранить некоторые данные приложения в файле? Я вызову метод «Сохранить» из соответствующего класса контроллера в моем методе нажатия кнопки.
Оттуда контроллер будет вызывать правильный набор операций из классов Service. Классы обслуживания в моем приложении действуют как интерфейс для уровня домена. Они будут проверять ввод, полученный от вызова метода контроллера (и, следовательно, от GUI), и манипулировать моделью данных.
После завершения проверки и манипулирования соответствующим объектом метод службы вернет код сообщения контроллеру. Например,
MessageCodes.SaveSuccess
. И контроллер, и классы обслуживания были основаны на объектах домена и / или общем наборе операций, которые могут быть сгруппированы вместе.Например:
FileMenuController
(операции: NewProject, SaveProject, LoadProject) ->ProjectServices
(CreateProject, PersistProjectToFile, LoadProjectFromFile). ГдеProject
будет класс домена в вашей модели данных. Классы Controller и Service в моем случае были неинстанцируемыми классами со статическими методами.Затем контроллер распознает операцию как завершение un / успешно. Теперь у контроллера есть своя собственная система обмена сообщениями, которую он использует для взаимодействия с уровнем представления, следовательно, существует двойная зависимость между уровнями обслуживания и представления. В этом случае класс, вызываемый
ViewState
вViewModels
пакете, всегда возвращается в GUI контроллером. Это состояние содержит такую информацию, как: « является ли состояние, которое вы пытались сделать приложением действительным? », « Удобочитаемое сообщение об операции, которую вы пытались выполнить, и почему она была или не удалась (сообщения об ошибках) » иViewModel
класс.ViewModel
Класс содержит соответствующие данные из области слоя , что графический интерфейс будет использовать для обновления вида. Эти модели представлений выглядят как доменные классы, но в моем случае я использовал очень узкие объекты. По сути, они практически не работают, просто передают информацию о низкоуровневом состоянии приложения. Другими словами, я НИКОГДА не собираюсь отдавать свои доменные классы на уровень представления. Это также объясняет , почемуControllers
иServices
пакеты разделить слой услуг на две части. Контроллеры никогда не будут обрабатывать классы домена или проверять их состояние. Они просто действуют как граница, преобразующая данные, относящиеся к графическому интерфейсу, в данные, относящиеся к области, которые могут использовать службы, и наоборот. Включение служебной логики в контроллер приведет к очень жирной контроллеры, которые сложнее обслуживать.Я надеюсь, что это дает вам отправную точку.
источник