Есть ли альтернатива инъекции ублюдка? (AKA инъекция бедного человека через конструктор по умолчанию) - PullRequest
115 голосов
/ 18 июля 2011

У меня чаще всего возникает соблазн использовать "инъекцию ублюдка" в некоторых случаях.Когда у меня есть «правильный» конструктор внедрения зависимостей:

public class ThingMaker {
    ...
    public ThingMaker(IThingSource source){
        _source = source;
    }

Но тогда для классов, которые я собираюсь использовать как публичные API (классы, которые будут использовать другие команды разработчиков), я могуникогда не находите лучший вариант, чем писать «ублюдочный» конструктор по умолчанию с наиболее вероятной необходимой зависимостью:

    public ThingMaker() : this(new DefaultThingSource()) {} 
    ...
}

Очевидным недостатком здесь является то, что это создает статическую зависимость от DefaultThingSource;в идеале такой зависимости не было бы, и потребитель всегда вводил бы любой IThingSource, который он хотел.Однако это слишком сложно для использования;потребители хотят создать ThingMaker и приступить к созданию вещей, а спустя несколько месяцев, когда возникнет такая необходимость, внедрить что-то еще.Это оставляет всего несколько вариантов на мой взгляд:

  1. Пропустить ублюдочный конструктор;заставить потребителя ThingMaker понять IThingSource, понять, как ThingMaker взаимодействует с IThingSource, найти или написать конкретный класс, а затем внедрить экземпляр в вызов их конструктора.
  2. Пропустите конструктор-ублюдок и предоставьте отдельную фабрику, контейнер или другой класс / метод начальной загрузки;каким-то образом заставить потребителя понять, что ему не нужно писать собственный IThingSource;вынудите потребителя ThingMaker найти и понять фабрику или загрузчик и использовать ее.
  3. Сохраните ублюдочный конструктор, позволяя потребителю «создавать» новый объект и запускать его, а также справляться с необязательной статической зависимостьюна DefaultThingSource.

Мальчик, # 3, конечно, кажется привлекательным.Есть ли другой, лучший вариант?Кажется, что № 1 или № 2 того не стоят.

Ответы [ 12 ]

0 голосов
/ 18 июля 2011

Наличие внутренней фабрики (внутренней для вашей библиотеки), которая отображает DefaultThingSource на IThingSource, который вызывается из конструктора по умолчанию.

Это позволяет вам «обновлять» класс ThingMaker без параметров или каких-либо знаний.IThingSource и без прямой зависимости от DefaultThingSource.

0 голосов
/ 18 июля 2011

Просто идея - возможно, немного более элегантная, но, к сожалению, не избавиться от зависимости:

  • удалить "ублюдочный конструктор"
  • в стандартном конструкторе, который вы делаетеисходный параметр по умолчанию равен нулю
  • , затем вы проверяете, является ли источник пустым, и если это так, вы присваиваете ему "новый DefaultThingSource ()" в других случаях, независимо от того, что потребитель вводит
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...