Я строю приложение WPF, используя шаблон MVVM. Прямо сейчас мои viewmodels вызывают сервисный уровень для извлечения моделей (как это не относится к viewmodel) и преобразования их в viewmodels. Я использую инъекцию конструктора, чтобы передать сервис, необходимый для модели представления.
Он легко тестируется и хорошо работает для моделей представления с небольшим количеством зависимостей, но как только я пытаюсь создать модели представления для сложных моделей, у меня появляется конструктор с большим количеством сервисов (один для извлечения каждой зависимости и список всех доступных значений). для привязки к itemsSource, например). Мне интересно, как обрабатывать несколько таких сервисов, и у меня все еще есть модель представления, которую я могу легко тестировать.
Я думаю о нескольких решениях:
Создание синглтона сервисов (IServices), содержащего все доступные сервисы в качестве интерфейсов. Пример: Services.Current.XXXService.Retrieve (), Services.Current.YYYService.Retrieve (). Таким образом, у меня нет огромного конструктора с кучей параметров сервисов.
Создание фасада для сервисов, используемых viewModel, и передача этого объекта в ctor моей viewmodel. Но тогда мне придется создать фасад для каждой из моих сложных моделей, и это может быть немного ...
Как вы думаете, что является «правильным» способом реализации такой архитектуры?
источник
new
для создания других моделей представлений, но представьте себе что-то столь же простое, как приложение MDI, где нажатие на кнопку или меню «новый документ» добавит новую вкладку или откроет новое окно. Оболочка / проводник должны иметь возможность создавать новые экземпляры чего-либо , даже если это скрыто за одним или несколькими слоями косвенного обращения.Ответы:
На самом деле оба эти решения плохие.
По сути, это шаблон локатора сервиса , который является анти-паттерном. Если вы сделаете это, вы больше не сможете понять, от чего на самом деле зависит модель представления, не взглянув на ее частную реализацию, что затруднит ее тестирование или рефакторинг.
Это не столько анти-паттерн, сколько запах кода. По сути, вы создаете объект параметра , но смысл паттерна рефакторинга PO состоит в том, чтобы иметь дело с наборами параметров, которые используются часто и во многих разных местах , тогда как этот параметр будет использоваться только один раз. Как вы упомянули, это привело бы к большому раздуванию кода без какой-либо реальной выгоды, и было бы плохо с большим количеством контейнеров IoC.
Фактически, обе вышеупомянутые стратегии не учитывают общую проблему, заключающуюся в том, что связь между моделями представления и сервисами слишком высока . Простое скрытие этих зависимостей в локаторе службы или объекте параметра фактически не меняет количество других объектов, от которых зависит модель представления.
Подумайте, как бы вы протестировали одну из этих моделей представлений. Насколько большим будет ваш установочный код? Сколько вещей нужно инициализировать, чтобы это работало?
Многие люди, начинающие с MVVM, пытаются создать модели представления для всего экрана , что в корне неверно. MVVM - это все о композиции , и экран с множеством функций должен состоять из нескольких разных моделей представлений, каждая из которых зависит только от одной или нескольких внутренних моделей / сервисов. Если им нужно общаться друг с другом, вы делаете это через pub / sub (брокер сообщений, шина событий и т. Д.)
Что вам действительно нужно сделать, так это провести рефакторинг моделей представлений, чтобы они имели меньше зависимостей . Затем, если вам нужен агрегатный «экран», вы создаете другую модель представления для агрегирования моделей меньшего размера. Эта модель агрегированного представления сама по себе не должна делать ничего особенного, поэтому она, в свою очередь, также довольно проста для понимания и тестирования.
Если вы сделали это правильно, это будет очевидно только из взгляда на код, потому что у вас будут короткие, сжатые, конкретные и тестируемые модели представления.
источник
Я мог бы написать книгу об этом ... на самом деле я;)
Во-первых, не существует универсально «правильного» способа делать вещи. Вы должны принять во внимание другие факторы.
Возможно, ваши услуги слишком мелкозернистые. Обертывание Сервисов с Фасадами, которые предоставляют интерфейс, который будет использовать конкретная Viewmodel или даже кластер связанных ViewModels, может быть лучшим решением.
Еще проще было бы заключить сервисы в единый Фасад, который используют все модели. Конечно, это может быть очень большой интерфейс с большим количеством ненужных функций для обычного сценария. Но я бы сказал, что он ничем не отличается от маршрутизатора сообщений, который обрабатывает каждое сообщение в вашей системе.
Фактически, то, что я видел во многих архитектурах, в конечном итоге превратилось в шину сообщений, построенную вокруг чего-то вроде шаблона Event Aggregator. Тестирование там легко, потому что ваш тестовый класс просто регистрирует слушателя в советнике и запускает соответствующее событие в ответ. Но это прогрессивный сценарий, который требует времени, чтобы расти. Я говорю начать с объединяющего фасада и идти оттуда.
источник
Почему бы не объединить оба?
Создайте фасад и разместите все сервисы, которые используют ваши viewmodels. Тогда вы можете иметь единый фасад для всех ваших моделей просмотра без плохого слова S.
Или вы можете использовать инъекцию свойств вместо конструктора. Но тогда вам нужно убедиться, что их вводят правильно.
источник