Випадково я працюю над проектом WinForms, який є візерунком після MVC. Я б не назвав це ідеальною відповіддю, але я поясню свій загальний дизайн і, сподіваюся, це допоможе вам придумати свій власний.
На основі прочитання, яке я зробив перед початком цього проекту, здається, що немає "правильного" способу його втілення. Я дотримувався простих принципів проектування OOP та MVC, а решта - пробні помилки, коли я розробляв робочий процес.
Чи просто MVC невідповідна архітектура для цього випадку використання?
Ні ..? У вашому запитанні недостатньо контексту, щоб дати пряму відповідь на це. Чому ви в першу чергу використовуєте MVC? Які нефункціональні вимоги вашого проекту? Ваш проект буде дуже важким у користувальницькому інтерфейсі? Ви більше піклуєтесь про безпеку та скоріше шарувату архітектуру? Які основні компоненти вашого проекту? Можливо, для кожного компонента потрібна інша модель дизайну. Дізнайтеся, чому ви хочете використовувати цей шаблон дизайну в першу чергу, і ви можете відповісти на власне запитання;)
Моя причина використання MVC: його досить проста модель дизайну, яку можна зрозуміти, на мій погляд, і моя конструкція ґрунтується на взаємодії з користувачем. Те, як MVC дозволяє розробнику окремо висловлювати проблеми, є достатнім і для моєї заявки. Це робить мій код набагато більш ретельним і перевіреним.
Я також припускаю, що я використовую більше гібридного дизайну. Зазвичай ідеальна концепція, представлена в інженерії програмного забезпечення, насправді не реалізується на практиці. Ви можете змінити дизайн відповідно до потреб вашого проекту. Не потрібно зациклюватися на тому, що правильно чи неправильно. Існують загальні практики, але правила завжди можна зігнути або порушити до тих пір, поки ви не стріляєте собі в ногу.
Моя реалізація почалася з дизайну високого рівня, який дав мені уявлення про те, які компоненти мені знадобляться. Найкраще починати саме так і працювати в напрямку архітектури. Ось пакетна схема проекту (створеного в StarUML):
Зауважте, що кожен шар, крім шару презентації, залежить від системи обміну повідомленнями. Це загальна "мова", яку нижні шари та підсистеми цих шарів використовують для спілкування один з одним. У моєму випадку це було просте перерахування на основі операцій, які можна виконати. Що підводить мене до наступного моменту ...
Подумайте про операції або команди як основу для вашої реалізації. Що ви хочете робити у вашій заяві? Розбийте його на найбільш фундаментальні операції. Наприклад: CreateProject, WriteNotes, SaveProject, LoadProject і т. Д. У графічному інтерфейсі (або в класах форм) відбудеться деяка подія (наприклад, натискання кнопки). Кожна операція має пов'язаний з нею метод контролера. У цьому випадку щось на кшталт Виходу занадто просто. Додаток можна просто закрити з класу Form. Але припустимо, що я хотів спочатку зберегти деякі дані програми у файлі? Я зателефоную методу "Зберегти" з відповідного класу контролера в межах мого методу натискання кнопки.
Звідти контролер викличе правильний набір операцій із класів Сервісу. Класи обслуговування в моїй програмі виконують функції інтерфейсу до доменного рівня. Вони перевірять вхід, отриманий від виклику методу контролера (і, таким чином, від GUI), і маніпулюють моделлю даних.
Після завершення перевірки та маніпуляції відповідним об'єктом сервісний метод поверне код повідомлення в контролер. Наприклад, MessageCodes.SaveSuccess
. І контролер, і класи обслуговування базувалися на об'єктах домену та / або на загальному наборі операцій, які можна об'єднати.
Наприклад: FileMenuController
(операції: NewProject, SaveProject, LoadProject) -> ProjectServices
(CreateProject, PersistProjectToFile, LoadProjectFromFile). Де Project
був би доменний клас у вашій моделі даних. Класи контролерів та сервісу в моєму випадку були немоментальними класами статичними методами.
Потім контролер визнає операцію завершеною un / успішною. Тепер контролер має власну систему обміну повідомленнями, яку він використовує для взаємодії з презентаційним шаром, отже, подвійна залежність між рівнями Сервіс та Презентація. У цьому випадку клас, викликаний ViewState
у ViewModels
пакеті, завжди повертається до GUI контролером. Цей стан містить інформацію на зразок: " це стан, в якому ви намагалися поставити програму дійсною? ", " Зрозуміле для людини повідомлення про операцію, яку ви намагалися виконати, і чому це було чи не було успішним (повідомлення про помилку) " та ViewModel
клас.
ViewModel
Клас містить відповідні дані з області шару , що графічний інтерфейс буде використовувати для поновлення виду. Ці моделі подання виглядають як доменні класи, але в моєму випадку я використовував дуже худі об'єкти. В основному вони практично не мають поведінки, просто передають інформацію про стан програми нижчого рівня. Іншими словами, я НІКОЛИ не збираюся роздавати свої доменні класи презентаційному шару. Ось чому Controllers
і Services
пакети розділяють сервісний шар на дві частини. Контролери ніколи не будуть обробляти доменні класи або перевіряти їх стан. Вони просто виконують функцію кордону, що перетворює відповідні дані графічного інтерфейсу у дані, що стосуються домену, які сервіси можуть використовувати, і навпаки. Включення логіки обслуговування в контролер призведе до дуже жирності контролери, які важче підтримувати.
Сподіваюся, це дає тобі вихідну точку.