Внедрение зависимостей (DI) зависит от интерфейсов?

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

В частности, в случае класса, который имеет определенный интерфейс в качестве параметра в своем конструкторе или определенный интерфейс, определенный как свойство (он же Setter), инфраструктура DI может передать экземпляр конкретного класса для удовлетворения потребностей. этого интерфейса в этом классе. (Извините, если это описание неясно. У меня возникли проблемы с описанием этого правильно, потому что терминология/концепции все еще несколько новы для меня.)

Причина, по которой я спрашиваю, заключается в том, что в настоящее время у меня есть класс, который имеет своего рода зависимость. Не столько зависимость от объекта, сколько URL. Класс выглядит так [C#]:

using System.Web.Services.Protocols;
public partial class SomeLibraryService : SoapHttpClientProtocol 
{
        public SomeLibraryService() 
        {
            this.Url = "http://MyDomainName.com:8080/library-service/jse";
        }
}

Класс SoapHttpClientProtocol имеет свойство Public с именем Url (которое представляет собой старую простую «строку»), и здесь конструктор инициализирует его жестко запрограммированным значением.

Могу ли я использовать структуру DI для ввода другого значения при построении? Я думаю, что нет, поскольку this.Url не является каким-либо Interface; это String.

[Кстати, приведенный выше код был "автоматически сгенерирован wsdl", согласно комментариям в коде, с которым я работаю. Так что я не особо хочу менять этот код, хотя и не вижу себя в его повторной генерации. Так что, возможно, изменить этот код можно.]

Я мог бы представить себе создание альтернативного конструктора, который принимает строку в качестве параметра и таким образом инициализирует this.Url, но я не уверен, что это правильный подход к сохранению слабо связанного разделения задач. (система на кристалле)

Любой совет для этой ситуации?


person Pretzel    schedule 15.07.2010    source источник


Ответы (4)


Не обязательно использовать интерфейсы — вы можете использовать конкретные типы или абстрактные базовые классы. Но многие преимущества DI (например, возможность изменить реализацию зависимости) проявляются при использовании интерфейсов.

Castle Windsor (структура DI, которую я знаю лучше всего) позволяет вам сопоставлять объекты в контейнере IoC с интерфейсами или просто с именами, которые будут работать в вашем случае.

person James Curran    schedule 15.07.2010
comment
Я ставлю вам зеленую галочку, но ответы Дэвида и Питера также были очень хорошими. Спасибо за разъяснение, что интерфейсы не требуются. - person Pretzel; 15.07.2010
comment
... при использовании интерфейсов это неверно или вводит в заблуждение. Я думаю, либо удалите это, либо подкрепите его тем, как использование абстрактного базового класса помешает мне изменить реализацию зависимости. - person Luke Puplett; 12.04.2019
comment
@LukePuplett: Если бы вы использовали фиктивную среду для создания объектов для модульного тестирования (одно из основных оправданий для DI), вам нужно было бы использовать интерфейс. - person James Curran; 17.04.2019
comment
@JamesCurran Нет, как и создание подклассов полиморфизма вручную, насмешка работает с теми же ограничениями; члены должны быть абстрактными или виртуальными. Как отмечает Дэвид, DI — это действие по предоставлению зависимостей классу или системе, которые должны использоваться, даже вручную, без автоматизированного контейнера DI, такого как Unity. Что касается вашего вопроса, я не использую библиотеки для насмешек. Я пишу действительно хорошие подделки и тестирую только поведение общедоступного API, что позволяет мне легко и часто проводить рефакторинг. Насмешка скрывает тесты и связывает тесты с реализацией. Необходимость издеваться над своим собственным кодом является признаком недостатка дизайна. - person Luke Puplett; 24.04.2019

DI на самом деле просто означает, что класс не будет создавать свои внешние зависимости и не будет управлять временем жизни этих зависимостей. Зависимости могут быть введены либо через конструктор, либо через параметр метода. Интерфейсы или абстрактные типы распространены для уточнения контракта, который потребитель ожидает от своей зависимости, однако в некоторых случаях могут быть внедрены и простые типы.

Например, класс в библиотеке может вызывать HttpContext.Current внутренне, что делает произвольные предположения о приложении, в котором будет размещаться код. Версия библиотечного метода DI ожидает, что экземпляр HttpContext будет внедрен через параметр и т. д.

person David    schedule 15.07.2010

Внедрение зависимостей — это способ организации вашего кода. Возможно, часть вашего замешательства связана с тем, что нет ни одного официального способа сделать это. Этого можно добиться с помощью "обычного" кода C# или с помощью такой инфраструктуры, как Castle Windsor. Иногда (часто?) это связано с использованием интерфейсов. Независимо от того, как это достигается, общая цель DI обычно состоит в том, чтобы сделать ваш код более легким для тестирования и последующего изменения.

Если бы вы вводили URL-адрес в свой пример через конструктор, это можно было бы считать «ручным» внедрением зависимостей. В статье Википедии о внедрении зависимостей есть больше примеров ручного и интегрированного внедрения зависимостей.

person Peter Recore    schedule 15.07.2010
comment
Да, я согласен. Некоторая путаница возникает из-за отсутствия стандартизированного способа сделать это. DI был представлен мне через книгу Pro ASP.net MVC Framework (автор Сандерсон), и каждый показанный пример использует интерфейсы, поэтому я пришел к выводу, что он работал только с интерфейсами, но логически это не имело смысла в моей голове, поэтому Я должен был спросить. Сандерсон рассказывает о замке Виндзор в своей первой книге, но теперь использует Ninject во втором издании (которое только что вышло из типографии на прошлой неделе). И да, я начинаю понимать, что DI очень помогает при модульном тестировании. - person Pretzel; 15.07.2010

Я хотел бы ответить, сосредоточив внимание на использовании интерфейсов в приложениях .NET. Полиморфизм в .NET может быть достигнут с помощью виртуальных или абстрактных методов или интерфейсов.

Во всех случаях существует сигнатура метода вообще без реализации или с реализацией, которую можно переопределить.

«Контракт» функции (или даже свойства) определен, но то, как реализуется метод, логическая сущность метода может быть разной во время выполнения, определяемой тем, какой подкласс создается и передается методу или конструктору, или установить на собственность (акт «инъекции»).

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

Однако следует соблюдать осторожность, чтобы не добавить никакой логики. Искушение сделать это сжигало людей в прошлом, так что многие люди используют интерфейсы - многие другие люди используют интерфейсы просто потому, что это то, что делают программисты, сидящие вокруг них.

Также интересно отметить, что, хотя сам DI редко используется чрезмерно, использование фреймворка для выполнения внедрения довольно часто чрезмерно используется в ущерб повышенной сложности, может иметь место цепная реакция, когда требуется все больше и больше типов. в контейнере, даже если они никогда не «переключались».

Инфраструктуры IoC следует использовать с осторожностью, обычно только тогда, когда вам нужно подкачивать объекты во время выполнения в соответствии со средой или конфигурацией. Обычно это означает переключение «швов» основных компонентов в приложении, таких как объекты репозитория, используемые для абстрагирования вашего уровня данных.

Для меня реальная сила инфраструктуры IoC заключается в переключении реализации в местах, где у вас нет контроля над созданием. Например, в ASP.NET MVC создание класса контроллера выполняется фреймворком ASP.NET, поэтому внедрить что-либо невозможно. Платформа ASP.NET имеет некоторые хуки, которые могут использоваться платформами IoC, чтобы «встать между» процессом создания и выполнить свою магию.

Люк

person Luke Puplett    schedule 15.11.2013
comment
См. «Двоичные критические изменения» в этой статье. docs.microsoft.com/en-us/dotnet/ standard/library-guidance/, в котором рекомендуется использовать абстрактные базовые классы вместо интерфейсов. - person Luke Puplett; 12.04.2019