Инъекция зависимости от абстрактной фабрики - выбор правильного шаблона
Я разрабатываю инструмент, который переносит проблемы со старой системы отслеживания проблем на новую. Я разделил все с помощью интерфейсов, но я не уверен, что это лучший способ склеить их вместе. У меня есть 3 зависимости, которые требуют данных времени выполнения:
- INewSystemClient - клиент для подключения к новой системе
- IRetryStrategy - обрабатывает таймауты и повторные попытки
- IMigrationSettings
Эти 3 зависимости являются зависимостями многих других. Я не мог придумать другой способ склеить все, чем зарегистрировать эти 3 как синглтоны (через DI-контейнер). Я также знаю, что синглтоны считаются плохим паттерном, поэтому я подумываю перейти на абстрактную фабрику.
Пример отношений, которые заставили меня использовать синглтон:
- Dependency1 (INewSystemClient client, ...) // конструктор для Dependency1
- Dependency2 (клиент INewSystemClient, ...) // конструктор для Dependency2
INewSystemClient требует данных времени выполнения, таких как пользователь, pw, host и т. Д.
Должен ли я переключиться на абстрактную фабрику и заставить фабрику создавать объекты вместо DI-контейнера?
2 ответа
Я думаю, что вы вводите в заблуждение термины, точно так же, как шаблон Singleton (большинство говорят, что сейчас это анти-шаблон) - это не то же самое, что экземпляр Singleton в вашем IOC, абстрактный шаблон фабрики - это не то же самое, что фабрика DI. То, о чем вам нужно подумать, - это области видимости или когда объект создается и удаляется.
В вашем настольном приложении может быть несколько областей действия, в которых вы можете зарегистрировать объект (на уровне приложения или "одноэлементном", на уровне модуля, на уровне потока, на уровне страницы...) Это обычно зависит от фреймворк, который вы используете (Prism, MvvmLight, caliburn.micro...), если вы создаете свою собственную систему, вы можете посмотреть, как это сделали некоторые другие фреймворки. Я знаю, что в Unity есть крутой способ обработки фабрик и ленивых инициализаций.
Обычно одноэлементный экземпляр лучше всего использовать для вещей, которые не будут доступны в нескольких потоках, которые изменят некоторые значения. Это когда вам нужно создать блокировки, и вы можете сильно замедлить процесс, например, заблокировать ваш поток пользовательского интерфейса. Например, если у вас есть HttpClient, который просто вызывает один API-интерфейс бэкэнда, который может использовать каждый, имеет смысл сделать его одноэлементной областью.
Например, если вы хотите записать в базу данных, вам может потребоваться другой контекст EF для каждой страницы, чтобы отслеживание сущностей не происходило на двух страницах.
У меня есть 3 зависимости, которые требуют данных времени выполнения:
Из вашего вопроса неясно, как эти зависимости потребляют данные времени выполнения. Если они требуют этого во время инициализации, это запах кода. Если вы передаете эти данные времени выполнения через вызовы методов уже инициализированных (и неизменяемых) классов, это вполне нормально.
Я также знаю, что синглтоны считаются плохим паттерном, поэтому я подумываю перейти на абстрактную фабрику.
Филипп Кордас уже коснулся этого, но я хотел бы повторить: вы путаете две вещи. Когда дело доходит до применения DI, шаблон Singleton - это плохо, но иметь один экземпляр некоторого класса во время выполнения (он же Singleton Lifestyle) вполне нормально. Некоторые (как и я) предпочитают, чтобы все компоненты были зарегистрированы в Singleton Lifestyle, так как это вызывает неизменность и отсутствие состояния, что упрощает регистрацию и предотвращает все виды распространенных неправильных конфигураций, таких как зависимые зависимости.
Должен ли я переключиться на абстрактную фабрику и заставить фабрику создавать объекты вместо DI-контейнера?
Как объясняется здесь, абстрактные фабрики, как правило, не являются правильным решением, и я считаю их запахом кода. Как правило, они используются для создания компонентов приложения с использованием данных времени выполнения, но, как было указано ранее, компоненты приложения не должны требовать данных времени выполнения во время построения.