Страницы

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

понедельник, 13 мая 2019 г.

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

Взялся я за реализацию 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


Ответ

В первую очередь - неверно ваше желание обойтись минимальным количеством регистраций компонентов. Если у вас 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. Я присоденияюсь к этому совету, почитайте - не пожалеете.

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

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