
Летучая
30.06.2017
18:31:15
Щас будет длиннопост
Возьмем например мввм для увп/впф. Что делать, когда приложение очень сильно разрастается? Становится нужно это, нужно то, и вот это прикрутить, и получается, что с течением времени поддерживать всю полученную лапшу становится очень сложно. Окидываю щас взглядом сильно связные компоненты своего пет-приложения и думаю, ведь зачем-то же Б-г дал нам интерфейсы, DI, IoC-контейнеры. Но как лучше всю эту братию использовать в десктопных/мобильных нативных приложениях?
Можно биндить вьюхи не на конкретные классы, а на интерфейсы, это удобно, поскольку в будущем такое приложение можно будет с лёгкостью расширить, написать новые вьюмодели для этих вьюх с другим поведением (например одинаковый интерфейс текстбокса, но с разными вьюмоделями => можно использовать один UI для бокса сообщений, комментов туда, комментов сюда, диалоговых окон обратной связи).
Но также Б-г дал нам shared-прожекты, в которых можно хранить вьюмодели и шарить их между разными UI-провайдерами — андроидовским, эппловским, увпшным или каким-нибудь другим.
Однако какой подход лучше избрать, когда приложение очень большое? Более ста вьюмоделей хранить в папке ViewModels, как завещал нам Caliburn.Micro, как-то некруто, путано, эти списки файлов листать можно с ума свихнуться и спутаться. То же самое с вьюхами. Получается, следует структуру разбить на модули-неймспейсы и выстроить иерархию типа:
- ViewModels [separate project]
-- Audio
--- AudioCollectionViewModel
--- AudioPageViewModel
--- AudioItemViewModel
-- Video
--- <...>
- Views [separate project]
-- Audio
--- AudioView
--- AudioShareView
-- Video
--- <...>
С таким подходом становится возможно шарить кодовую базу между разными UI-провайдерами и при этом она довольно проста и очевидна. Но что тогда делать с DI и биндами контролов на интерфейсы? Заметив, что проект может неконтролируемо расширяться, стоит ли делать ещё один проект-схему или же интерфейсы вью-моделей следует складывать вместе вьюхами приложения? Или с вьюмоделями? Пожалуй, этот вариант логичнее всего. Но необходимо ли для каждого класса выделать интерфейс и нигде не использовать прямых биндингов на инстансы? Ведь вдруг нам понадобится использовать несколько реализаций поведения одного и того же элемента управления (а еще один такой же элемент управления нам копипастить лень — и это антипаттерно).
Что мы получим, имея ввиду всё вышесказанное? Какова будет структура нашего нового проекта со слабой связностью компонентов? Попробуем разобраться!
- ViewModels [shared project]
-- Audio
--- Implementation
---- AudioCollectionViewModel
---- AudioPageViewModel
---- AudioViewModel
--- IAudioCollectionViewModel
--- IAudioPageViewModel
--- IAudioViewModel
Соответственно во всех компонентах реализованных моделек мы обмазываемся выделенными интерфейсами и слабо связываем наши компоненты, ни в коем случае не используя ключевое слово new (конечно же, потому что это антипаттерн). Получилось у нас всё просто, тестируемо и по фен-шую (ну, почти). Некоторые интерфейсы можно явно не описывать (например, IAudioCollectionViewModel), если они являются потомками generic-класса (например, IFetchableCollection<IAudioCollectioViewModel>). Итого мы ещё чуть-чуть упростили себе жизнь. Или такое всё же лучше описать явно, что думаете?
Далее встаёт главный вопрос — чем инстансить классы наших вьюмоделей, где инстансить классы вьюмоделей, как инстансить классы вьюмоделей. Из того, что я знаю, получается, что все конструкторы инжектируемых и принимающих инъекцию моделей должны быть без лишних параметров. То есть мы хардкодим в классе его поведение и особенность, а при шаге вправо - шаге влево делаем другой класс, который реализует нужный интерфейс. Ок, удобно и вроде бы по паттернам. Но есть вот у нас хамлы, в которые надо закинуть нужные вьюмодели. Что делать-то?
<SampleView.DataContext>
<SampleViewModel />
</SampleView.DataContext>
Инжектируем прямо в Уихе (одним лёгким движением руки убивая слабую связность компонентов)? Или ViewModelLocator с ужасно громоздким описанием лейзи-инстансов наших моделей (по понятным причинам это тоже антипаттерн)? Или всё-таки делать конструктор с параметром, чтобы потом где-нибудь (где?) выполнить IoC.Resolve<ISampleViewModel>? Вот этот вариант, кажется, самый вкусный. И всё же, если сервис-локатор и вьюмодел-локатор — антипаттерны, то где же нам резолвить это это добро? В конструкторе вьюхи, в код-бихайнде?
public SampleView {
public SampleView() {
this.InitializeComponent();
this.DataContext = IoC.Resolve<ISampleViewModel>();
}
}
Однако нередко в чатах слышны громкие заявления, что идеальный MVVM — это когда код-бихайнд не содержит ничего, кроме InitializeComponent(). Для меня в иок-контейнерах пока самый сложный и непонятный момент — это отсутствие явного ответа на вопрос КОГДА их использовать в контексте ГДЕ их использовать.

Gid
30.06.2017
18:50:21
Если серьезно то как бы смысла нет
То есть дело даже не в самих технологиях или ПО
Не в подходах
А именно в надобности и модели распространения
Плюс уязвимости ПО вроде Me.doc
Которые привели к распростанению Пети