Хранение контейнерного DI использования в составе базируется в Silverlight и MVVM

Мне не совсем ясно, как я могу разработать так, я сохраняю ссылку на контейнер DI в составе, поддерживают Silverlight + приложение MVVM.

У меня есть следующий простой сценарий использования: существует основное представление (возможно, список объектов) и действие для открытия представления редактирования для одного единственного объекта. Таким образом, основное представление должно создать и показать представление редактирования, когда пользователь принимает меры (например, нажимает некоторую кнопку).

Для этого у меня есть следующий код:

public interface IView
{
   IViewModel ViewModel {get; set;}
}

Затем для каждого представления, что я должен смочь создать, у меня есть абстрактная фабрика, как так

public interface ISomeViewFactory
{
   IView CreateView();
}

Эта фабрика затем объявляется зависимостью "родительской" модели представления, как так:

public class SomeParentViewModel
{
   public SomeParentViewModel(ISomeViewFactory viewFactory)
   {
       // store it
   }

   private void OnSomeUserAction()
   {
      IView view = viewFactory.CreateView();
      dialogService.ShowDialog(view);
   }       
} 

Таким образом, все хорошо до здесь, никакой контейнер DI в поле зрения :). Теперь прибывает реализация ISomeViewFactory:

public class SomeViewFactory : ISomeViewFactory
{
    public IView CreateView()
    {
        IView view = new SomeView();
        view.ViewModel = ????   
    }
}

"????" часть является моей проблемой, потому что модель представления для представления должна быть разрешена от контейнера DI, таким образом, это ввело свои зависимости. То, что я не знаю, - то, как я могу сделать это, не имея зависимости к контейнеру DI нигде кроме корня состава.

Одно возможное решение состояло бы в том, чтобы иметь любого зависимость от модели представления, которая введена в фабрику, как так:

public class SomeViewFactory : ISomeViewFactory
{
    public SomeViewFactory(ISomeViewModel viewModel)
    { 
       // store it
    }

    public IView CreateView()
    {
        IView view = new SomeView();
        view.ViewModel = viewModel;
    }
}

В то время как это работает, это имеет проблему, что, так как целый граф объектов обеспечен электричеством "статически" (т.е. "родительская" модель представления получит экземпляр SomeViewFactory, который получит экземпляр SomeViewModel, и они будут жить пока "родительские" жизни модели представления), введенная реализация модели представления с сохранением информации и если пользователь откроет дочернее представление дважды, во второй раз, то когда модель представления будет тем же экземпляром и иметь состояние до. Я предполагаю, что мог работать вокруг этого с "Инициализировать" методом или чем-то подобным, но это не пахнет совершенно правильным.

Другое решение могло бы состоять в том, чтобы перенестись, контейнер DI и иметь фабрики зависят от обертки, но это все еще был бы контейнер DI, "скрытый" там :)

PS: мое текущее решение состоит в том, что фабрики знают о контейнере DI, и это - только они и корень состава, которые имеют эту зависимость.

13
задан ROMANIA_engineer 1 December 2017 в 14:50
поделиться

1 ответ

Чтобы максимально приблизиться к вашему примеру кода, вы можете ввести еще один уровень косвенности в форме IViewPopulator:

public interface IViewPopulator
{
    void Populate(IView view);
}

Теперь вы можете реализовать свой SomeViewFactory следующим образом:

public class SomeViewFactory : ISomeViewFactory
{
    private readonly IViewPopulator populator;

    public SomeViewFactory(IViewPopulator populator)
    {
        if (populator == null)
        {
            throw new ArgumentNullException("populator");
        }

        this.populator = populator;
    }

    public IView CreateView()
    {
        IView view = new SomeView();
        this.populator.Populate(view);
        return view;
    }
}

Это разделяет создание представлений и совокупность ViewModels, придерживаясь принципа единой ответственности . В определенной степени это также пример агрегирования сервисов .

Теперь вы можете реализовать IViewPopulator как конкретный тип, который принимает обычные зависимости:

public class SomeViewPopulator : IViewPopulator
{
    private readonly IDependency dep;

    public SomeViewPopulator(IDependency dep)
    {
        if (dep == null)
        {
            throw new ArgumentNullException("dep");
        }

        this.dep = dep;
    }

    public void Populate(IView view)
    {
        var vm = // Perhaps use this.dep to create an instance of IViewModel...
        view.ViewModel = vm;
    }
}

Вероятно, будут другие способы моделирования отношений между IView и IViewModel, но приведенное выше представляет одно из возможных решений.

Главное - продолжать извлекать абстракции до тех пор, пока у каждой из них не будет четко определена ответственность. Это упражнение на самом деле не о том, чтобы сделать код независимым от контейнера, а о соблюдении принципов SOLID.

7
ответ дан 2 December 2019 в 01:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: