Страницы

Поиск по вопросам

вторник, 25 февраля 2020 г.

Применение внедрения зависимостей. Правильно ли?

#c_sharp #net #dependency_injection


Взялся я за реализацию IoC для сервиса данных. Сделал вот так:

interface IDataService
{

}


и его реализация (возьмем для примера RpcJson):

class JsonRpcDataService : IDataService
{

}


Далее регистрируем их в IoC-контейнере. Тут все пока понятно.

Далее переходим к собственно к реализации. Я определил следующую структуру сервиса
данных:


Модели - тут все понятно
Коллекторы - это вспомогательные классы для получения данных
Обработчики - вспомогательные классы для обработки данных (сохранения, например)


Опишем интерфейс модели:

interface IBook
{
   string Autor { get; set; }
   ...
}


Коллектор:

interface IBooksCollector
{
   IEnumerable GetItems();
   ...
}


И обработчик:

interface IBooksHandler
{
   void Save(IBook book);
   ...
}


Ну и, соответственно, для реализуем каждый из них для JsonRpc. Далее дополняем интерфейс
IDataService:

interface IDataService
{
   IBook CreateBook();

   IBooksCollector CreateBooksCollector();

   IBooksHandler CreateBooksHandler();
}


И реализуем эти методы в JsonRpcDataService. Их я сделал для того, чтобы я на уровне
ViewModel должен был бы связывать только IDataService с RpcJsonDataService, а не все
интерфейсы с их реализациями. Чтобы в итоге я мог делать как-то так:

var dataService = IoC.Resolve();
// Создаем модель
IBook book = dataService.CreateBook(); 


Вместо 

IBook book = IoC.Resolve();


и где-то до этого связывание

IBook book = IoC.Register();


где Book - реализация IBook для RpcJson. Так как моделей может быть очень много,
то вместо кучи строк вида:

IoC.Register();


Все сводится к одной:

IoC.Register();


По ходу у меня появились вопросы, на которые я и прошу Вас ответить:


Правилен ли такой подход с созданием инстансов? Или может сделать фабрики вида CreateModel(),
в которую в качестве параметра T будет передаваться интерфейс, а фабрика уже будет
решать что "отдать"?
Стоит ли вообще делать интерфейсы для моделей, или лучше описать их сразу? Выделил
я их для того, чтобы не загромождать из атрибутами вида [JsonProperty(...)], необходимые
для сериализации, ведь эти атрибуты нужны только для сервера RpcJson

    


Ответы

Ответ 1



В первую очередь - неверно ваше желание обойтись минимальным количеством регистраций компонентов. Если у вас 40 компонентов нет ничего зазорного в том чтобы регистрировать все 40 компонентов в контейнере. Это не будет ошибкой. Более того, хотя многие контейнеры и поддерживают в том или ином виде автоматическую регистрацию компонентов, Castle Windsor например, насколько мне известно, обязывает вас явно регистрировать каждый компонент, и такой подход с явной регистрацией имеет определенный смысл. Но здесь вы вправе выбрать то что вам ближе - автоматическая регистрация или явная регистрация каждого компонента, оба подхода имеют свои преимущества и недостатки. Второе - вы ошибочно ассоциируете регистрацию компонента и последующее получение его из контейнера. Если вы написали IoC.Register(); это не означает что потом для получения IComponent вы обязаны получать его из контейнера. Как правило, вы регистрируете n - компонентов, но из IoC контейнера - запрашиваете только один. Например, если у вас ASP-MVC приложение, в нем может быть много компонентов (контроллеры, сервисы и т.д.), но запрос компонента из IoC контейнера у вас будет всего один - это будет запрос контроллера в фабрике контроллеров. Чтобы понять зачем регистрировать 10 компонентов, если запрашиваться будет только 1 читайте про основные паттерны внедрения зависимостей - внедрение конструктора и внедрение свойства. Ответы на ваши вопросы: Использование фабрик для создания моделей - нормальный подход. Создавать фабричный метод вида CreateModel() где T интерфейс модели, не имеет смысла. Подумайте, чем этот метод будет принципиально отличаться от аналогичного метода IoC-контейнера? Скорее всего не стоит делать интерфейсы для моделей. Использование IoC контейнера вовсе не обязывает вас делать интерфейсы для каждого класса в вашем приложении. Для моделей интерфейсы чаще всего не нужны. По формулировке вашего вопроса видно что вы довольно плохо ориентируетесь в теме и двигаетесь в неверном направлении. Вам стоит потратить немного времени на ее изучение, прежде чем проектировать приложение. В частности паттерны внедрения зависимостей, упомянутые выше (внедрение конструктора и внедрение свойства), существенно важнее для понимания DI, чем любые вопросы, связанные с регистрацией компонентов в IoC-контейнере. Вообще внедрение зависимостей это как раз про эти паттерны, а IoC-контейнер это просто инструмент, облегчающий построение приложения с использованием DI, и DI можно применять вообще без IoC-контейнера. В комменатриях @cybrex посоветовал прочитать книгу Симан М. - Внедрение зависимостей в .NET. Я присоденияюсь к этому совету, почитайте - не пожалеете.

Комментариев нет:

Отправить комментарий