Dependency Injection에 대한 최상의 정의는 무엇입니까?


10

누군가 나에게 다가 가서 개념적 방식으로 Dependency Injection을 정의하고 소프트웨어 디자인에서 DI를 사용하는 실제 장단점을 설명하도록 요청할 때마다. 나는 DI의 개념을 설명하기가 어렵다고 고백합니다. 나는 그들에게 단일 책임 원칙, 상속에 대한 구성 등에 관한 역사를 말할 필요가있을 때마다.

누구나 개발자를 위해 DI를 설명하는 가장 좋은 방법을 설명하는 데 도움을 줄 수 있습니까?


2
여기서의 문제는 DI에 대해 상충되는 정의가 너무 많다는 것입니다. "순수한 DI"자세를 취합니다. 모든 상태, 데이터 등을 제공하기 위해 해당 매개 변수에 의존하는 기능이있는 경우 해당 기능은 DI를 사용합니다. 다른 극단적 인 경우, 일부는 DI 프레임 워크가 없으면 의존성 주입이 없다고 주장 할 것입니다 (물론 그것은 잘못된 것입니다). 따라서 정의를 작성하지 않으면 그 정의를 설명 할 수 없습니다.
David Arno

내가 이해하는 것처럼 이것은 단지 내 문제가 아닙니다.
Tiago Sampaio



의존성 주입은 의존성 반전을 달성하는 데 사용되는 기술 중 하나입니다. 다른 모든 것은 그 위에 구축 된 추가 물건입니다. 이 두 용어에서 "종속성"이라는 단어는 약간 다른 의미를 갖습니다. 의존성 주입에서는 코드가 의존하는 구성 요소를 나타냅니다. 의존성 역전에서, 그것은 (지시 된) 관계 자체-우리가 반전시키고 싶은 관계를 말합니다. 후자는 목표이므로 주요 장단점은 동일합니다. 객체 수명 관리와 같은 실제 구현과 관련된 몇 가지 추가 문제.
Filip Milovanović

답변:


22

의존성 주입 은 다소 간단한 개념에 대한 끔찍한 이름 (IMO) 1 입니다. 예를 들면 다음과 같습니다.

  1. X를 수행하는 메소드 (또는 메소드가있는 클래스)가 있습니다 (예 : 데이터베이스에서 데이터 검색).
  2. X를 수행하는 과정에서 상기 방법은 내부 리소스 (예 : a DbContext)를 생성하고 관리합니다 . 이 내부 리소스는 종속성 이라고합니다.
  3. DbContext메소드에서 자원의 작성 및 관리 (예 :)를 제거 하고이 메소드를 자원을 제공하는 호출자의 책임 (메소드 매개 변수 또는 클래스의 인스턴스화)
  4. 이제 의존성 주입을 수행하고 있습니다.


[1] : 저수준의 배경에서 왔으며, 의존성 주입을 배우고 배우는 데 몇 달이 걸렸습니다. 이름은 DLL 주입 과 같이 훨씬 더 복잡 할 수 있기 때문 입니다. Visual Studio (및 일반적으로 개발자)는 종속성 이 전혀 도움이되지 않으므로 프로젝트가 의존 하는 .NET 라이브러리 (DLL 또는 어셈블리 )를 참조 합니다. Dependency Walker (depends.exe) 와 같은 것도 있습니다 .


[편집] 일부 데모 코드가 일부에는 유용 ​​할 것이라고 생각했습니다. 여기에 C #이 있습니다.

의존성 주입이없는 경우 :

public class Repository : IDisposable
{
    protected DbContext Context { get; }

    public Repository()
    {
        Context = new DbContext("name=MyEntities");
    }

    public void Dispose()
    {
        Context.Dispose();
    }
}

그런 다음 소비자는 다음과 같은 작업을 수행합니다.

using ( var repository = new Repository() )
{
    // work
}

의존성 주입 패턴으로 구현 된 동일한 클래스는 다음과 같습니다.

public class RepositoryWithDI
{
    protected DbContext Context { get; }

    public RepositoryWithDI(DbContext context)
    {
        Context = context;
    }
}

이제 인스턴스화하고 클래스에 DbContext전달 (errm, inject )하는 것은 호출자의 책임입니다 .

using ( var context = new DbContext("name=MyEntities") )
{
    var repository = new RepositoryWithDI(context);

    // work
}

3
Wikipedia에 추가해야합니다.
Evorlor 2019

2
이제 DbContext를 인스턴스화하는 것은 호출자의 책임 입니다. 필요한 모든 종속성을 인스턴스화하는 것은 애플리케이션의 진입 점에 대한 책임이라고 생각합니다. 따라서 소비자는 자신의 계약에 의존으로 필요한 유형을 도입하기 만하면됩니다.
Fabio

@Fabio 그럴 수 있습니다. (이 경우 호출자의 책임은 응용 프로그램 시작시 인스턴스화 된 리소스를 호출되는 메서드 / 클래스에 제공하는 것입니다.) 예를 들어, 의존성 주입 개념을 설명 할 필요는 없기 때문에 그렇지 않습니다. .
Marc.2377

5

추상적 개념은 종종 실제 세계 비유를 사용하여 더 잘 설명됩니다. 이것은 나의 비유입니다.

샌드위치 가게를 운영합니다. 당신은 놀라운 샌드위치를 ​​만들지 만 빵 자체에 대해서는 거의 알지 못합니다. 하얀 빵만 먹을 수 있습니다. 빵을 샌드위치로 만드는 데 사용하는 토핑에 전적으로 집중합니다.

그러나 일부 고객은 실제로 갈색 빵을 선호합니다. 일부는 통 곡물을 선호합니다. 어느 쪽이든 상관하지 않습니다. 비슷한 크기의 빵이라면 놀라운 샌드위치를 ​​만들 수 있습니다. 또한 여러 종류의 빵을 조달하고 재고를 유지해야하는 추가 책임을 감수하고 싶지도 않습니다. 여러 종류의 빵을 비축하더라도 합리적인 예측을 할 수없는 빵에 이국적인 맛이있는 고객이 항상있을 것입니다.

따라서 고객은 자신의 빵을 가져 오는 새로운 규칙을 제정합니다. 더 이상 빵을 직접 제공하지 않습니다. 이것은 상생의 상황입니다. 고객은 원하는 정확한 빵을 얻을 수 있으며, 더 이상 관심없는 빵을 구할 필요가 없습니다. 결국, 당신은 제빵사가 아닌 샌드위치 메이커입니다.

아, 그리고 자신의 빵을 사고 싶지 않은 고객을 수용하기 위해, 당신은 옆에 원래의 부드러운 흰 빵을 판매하는 두 번째 상점을 열었습니다. 자신의 빵을 가져 오지 않은 고객은 기본 빵을 가져와 샌드위치를 ​​만들기 위해 당신에게 와야합니다.

완벽하지는 않지만 주요 기능인 소비자에게 제어 기능을 강조합니다 . 본질적인 윈-윈은 더 이상 자신의 의존성을 얻을 필요가없고, 소비자는 자신의 의존성을 선택하는 데 방해가되지 않는다는 것입니다.


1
나는 이것을 좋아하지만 OP는 개발자 들을위한 설명 찾고있다 . 초기 추상화는 좋지만 조만간 실제 사례가 필요합니다.
로비 디

1
@RobbieDee : 패턴 의 목적 이 명확 할 때 구현도 명확 해집니다. 예를 들어 Marc의 대답은 절대적으로 정확하지만 설명이 그가 사용하는 예제 상황의 복잡한 특성으로 인해 혼란스러워하는 것 같습니다. 이 아래로 비등 "당신이 수집 나무에 사람을 선전하지 않는 배를 구축하고 작업 및 작업을 할당하지 않고, 바다의 끝없는 광대를위한 긴 그들에게 가르 칠합니다." . 무엇을해야하는지 설명하기보다는 왜해야하는지 설명 하는 것이 좋습니다.
Flater

2
물론 당신은 옳지 만 도움이 될 수는 없지만 실제적인 파일 시스템이나 데이터베이스가 없어서 식욕을 자극 할 수는 없지만 내 좁은 개발자의 견해와 같은 확실한 예가 필요하다고 생각합니다.
로비 Dee

1

그것에 대한 간단한 답변 :

무엇보다도 클래스는 잘 정의 된 책임을 가져야하며이 범위 밖의 모든 항목은 해당 클래스 외부에 유지해야합니다. 이렇게 말하면 Dependency Injection은 "제 3 자"의 도움을 받아 다른 클래스 B의 기능을 클래스 A에 주입하여 이러한 분리 문제를 해결함으로써 클래스 A가 범위를 벗어난 일부 작업을 완료하도록 도와줍니다.

.Net Core는이 프레임 워크가 많은 의존성 주입을 사용하기 때문에 제공 할 수있는 좋은 예입니다. 일반적으로 삽입하려는 서비스는 startup.cs파일에 있습니다.

물론, 학생은 다형성, 인터페이스 및 OOP 디자인 원칙과 같은 일부 개념을 알고 있어야합니다.


0

본질적으로 간단한 개념은 많은 보풀과 분쿰이 있습니다.

코드에서 간단하게 수행 할 수있을 때 " 어떤 프레임 워크를 사용해야 합니까?"라는 문제가 발생 하기 쉽습니다 .

이것은 내가 개인적으로 사용하는 정의입니다.

의존성 주입은 Y가없는 경우에도 Y의 인스턴스에 대한 기준을 만족시키는 모든 Y를 제공하는 기능을 포함합니다.

Y가 파일 시스템 또는 데이터베이스 연결 인 경우가 있습니다.

moq 와 같은 프레임 워크 는 인터페이스를 사용하여 이중 (Y의 척 버전)을 정의 할 수 있으므로 Y의 인스턴스에 삽입 할 수 있습니다. 여기서 Y는 데이터베이스 연결입니다.

이것이 순전히 단위 테스트 문제라고 생각하는 함정에 빠지기 쉽지만 변경이 예상되고 논쟁의 여지가있는 코드의 모든 비트에 매우 유용한 패턴입니다.


0

매개 변수를 통해 해당 동작을 함수에 삽입하는 방법을 통해 런타임시 함수의 동작을 제공합니다.

전략 패턴 은 의존성 주입의 훌륭한 예입니다.


0

이 작업을 올바르게 수행하려면 먼저 종속성 및 주입을 정의해야합니다.

  • 종속성 : 작업에 필요한 모든 리소스
  • 주입 : 일반적으로 메소드의 인수로 해당 자원을 조작에 전달합니다.

기본적인 예는 두 개의 값을 더하는 방법입니다. 분명히이 방법은 값을 추가해야합니다. 그것들을 인수로 전달하여 제공된다면, 이것은 이미 의존성 주입의 경우입니다. 대안은 피연산자를 속성 또는 전역 변수로 구현하는 것입니다. 이렇게하면 종속성이 주입되지 않고 외부에서 사전에 사용 가능합니다.

대신 속성을 사용하고 이름을 A와 B로 지정한다고 가정합니다. 이름을 Op1 및 Op2로 변경하면 Add 메서드가 중단됩니다. 또는 IDE가 모든 이름을 업데이트합니다. 요점은 메서드가 외부 리소스에 종속되어 있기 때문에 업데이트해야 할 시점입니다.

이 예제는 기본이지만 메소드가 이미지와 같은 객체에 대해 작업을 수행하거나 파일 스트림에서 읽는 더 복잡한 예제를 상상할 수 있습니다. 이미지의 위치를 ​​알아야하는 방법으로 이미지에 도달하기를 원하십니까? 아니요. 파일 자체를 여는 방법을 원하여 파일을 어디에서 찾아야하는지 또는 파일에서 읽을 것인지 알아야합니까? 아니.

요점 : 분석법의 기능을 핵심 행동으로 줄이고 환경과 분석법을 분리하는 것. 두 번째를 수행하여 첫 번째를 얻습니다.이를 종속성 주입의 정의로 간주 할 수 있습니다.

장점 : 분석법 환경에 대한 종속성이 제거되었으므로 분석법 변경은 환경에 영향을 미치지 않으며 그 반대도 마찬가지입니다. => 응용 프로그램을 유지 관리하기가 더 쉬워집니다 (수정).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.