По совпадению, я работаю над проектом WinForms, который создан по образцу MVC. Я бы не назвал это идеальным ответом, но я объясню мой общий дизайн, и, надеюсь, это поможет вам придумать свой собственный.
Судя по чтению, которое я сделал перед началом этого проекта, кажется, что нет «правильного» способа реализовать это. Я следовал простым принципам разработки ООП и 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
пакеты разделить слой услуг на две части. Контроллеры никогда не будут обрабатывать классы домена или проверять их состояние. Они просто действуют как граница, преобразующая данные, относящиеся к графическому интерфейсу, в данные, относящиеся к области, которые могут использовать службы, и наоборот. Включение служебной логики в контроллер приведет к очень жирной контроллеры, которые сложнее обслуживать.
Я надеюсь, что это дает вам отправную точку.