design-patterns 파이썬 c# - 의존성 주입이란 무엇입니까?





15 Answers

지금까지 발견 한 최고의 정의는 James Shore의 것입니다 .

"의존성 주입"은 5 센트 개념의 25 달러 용어입니다. [...] 의존성 주입이란 객체에 인스턴스 변수를주는 것을 의미합니다. [...].

마틴 파울러 (Martin Fowler ) 의 기사 또한 유용 할 수 있습니다.

의존성 주입은 기본적으로 객체가 필요로하는 객체 (의존성)를 객체 자체로 생성하는 대신에 제공합니다. 의존성을 조롱하거나 스터브 아웃 (stubbed) 할 수 있으므로 테스트에 매우 유용한 기술입니다.

의존성은 여러 가지 방법 (생성자 삽입 또는 설정자 삽입 등)을 통해 객체에 주입 할 수 있습니다. 하나의 특수 종속성 주입 프레임 워크 (예 : Spring)를 사용하여이를 수행 할 수도 있지만 반드시 필요하지는 않습니다. 이러한 프레임 워크에 종속성 주입이 필요하지 않습니다. 객체 (의존성)를 명시 적으로 인스턴스화하고 전달하는 것은 프레임 워크에 의한 주입만큼 좋은 주입입니다.

c++ php javascript

종속성 삽입 에 대한 특정 질문과 함께 게시 할 몇 가지 질문이 있습니다. 예를 들어 언제 사용하고 프레임 워크에 어떤 질문이 있습니까? 하나,

의존성 주입이란 무엇이며, 언제 / 왜 사용해야합니까, 사용하지 않아야합니까?




Dependency Injection은 내부적으로 구성하는 대신 다른 코드 조각에서 개체의 인스턴스를받는 방식으로 개체를 디자인하는 방식입니다. 즉, 객체가 필요로하는 인터페이스를 구현하는 객체는 코드를 변경하지 않고 대체 할 수 있으므로 테스트가 간단 해지고 디커플링이 향상됩니다.

예를 들어, 다음과 같은 클립을 고려하십시오.

public class PersonService {
  public void addManager( Person employee, Person newManager ) { ... }
  public void removeManager( Person employee, Person oldManager ) { ... }
  public Group getGroupByManager( Person manager ) { ... }
}

public class GroupMembershipService() {
  public void addPersonToGroup( Person person, Group group ) { ... }
  public void removePersonFromGroup( Person person, Group group ) { ... }
} 

이 예제에서, PersonService::addManagerPersonService::addManager PersonService::removeManager 의 구현은 GroupMembershipService 인스턴스가 필요하다. Dependency Injection이 없다면 GroupMembershipService 의 생성자에서 새로운 GroupMembershipService 를 인스턴스화하고 두 인스턴스에서 그 인스턴스 속성을 사용하는 것이 전통적인 방법 일 것이다. 그러나 GroupMembershipService 의 생성자에 여러 가지가 필요한 경우 또는 더 나쁜 경우에는 GroupMembershipService 에서 호출해야하는 초기화 "설정자"가 있고 코드가 빠르게 커지고 PersonService 이제 GroupMembershipService 뿐 아니라 GroupMembershipService 의존하는 다른 모든 것. 또한 GroupMembershipService 대한 연결은 GroupMembershipService 에 하드 코드되어 있습니다. 즉, 테스트 용도로 GroupMembershipService 를 "더미"하거나 응용 프로그램의 여러 부분에서 전략 패턴을 사용할 수 없다는 것을 의미합니다.

Dependency Injection을 사용하면 GroupMembershipService 에서 GroupMembershipService 를 인스턴스화하는 대신 PersonService 생성자에 전달하거나 Property (getter 및 setter)를 추가하여 PersonService 인스턴스의 로컬 인스턴스를 설정할 수 있습니다. 즉, PersonService 는 더 이상 GroupMembershipService 를 작성하는 방법에 대해 걱정할 필요가 없으며 주어진 GroupMembershipService 를 승인하고이를 사용하여 작업합니다. 이는 또한 GroupMembershipService 의 서브 클래스이거나 GroupMembershipService 인터페이스를 구현하는 것이 GroupMembershipService "주입"될 수 있으며 PersonService 는 변경 사항을 알 필요가 없음을 의미합니다.




낚시하러 가고 싶다고 상상해 봅시다.

  • 의존성 주입 없이는 모든 것을 스스로 처리해야합니다. 보트를 찾아 낚시대를 사거나 미끼를 찾아야합니다. 물론 가능하지만 많은 책임이 있습니다. 소프트웨어 용어로,이 모든 것을 검색해야한다는 의미입니다.

  • 의존성 주입을 사용하면 다른 누군가가 모든 준비 작업을 처리하고 필요한 장비를 사용할 수 있습니다. 보트, 낚싯대 및 미끼를 사용할 준비가되어 있습니다.




This 내가 본 Dependency InjectionDependency Injection Container 에 대한 가장 간단한 설명입니다.

의존성 주입없이

  • 응용 프로그램에는 Foo (예 : 컨트롤러)가 필요하므로 다음을 수행하십시오.
  • 응용 프로그램이 Foo를 만듭니다.
  • 응용 프로그램 호출 Foo
    • Foo가 Bar (예 : 서비스)를 필요로하므로 다음을 수행합니다.
    • 푸가 바 생성
    • Foo는 Bar에게 전화를 겁니다.
      • Bar는 Bim (서비스, 저장소, ...)을 필요로하므로 다음을 수행합니다.
      • 바가 Bim을 만듭니다.
      • 바는 뭔가를한다.

의존성 주입

  • 응용 프로그램에는 Boo가 필요한 Foo가 필요합니다. Bim이 필요합니다.
  • 응용 프로그램이 Bim을 만듭니다.
  • 응용 프로그램은 Bar를 생성하고 Bim에게줍니다.
  • 응용 프로그램은 Foo를 생성하고 바를 제공합니다.
  • 응용 프로그램 호출 Foo
    • Foo는 Bar에게 전화를 겁니다.
      • 바는 뭔가를한다.

의존성 주입 컨테이너 사용

  • 응용 프로그램에 Foo가 필요합니다.
  • 응용 프로그램은 Container에서 Foo를 가져 오므로 다음과 같이됩니다.
    • 컨테이너가 Bim을 만듭니다.
    • 컨테이너가 Bar를 생성하고 Bim에게줍니다.
    • Container가 Foo를 만들고 Bar에게 준다.
  • 응용 프로그램 호출 Foo
    • Foo는 Bar에게 전화를 겁니다.
      • 바는 뭔가를한다.

의존성 주입의존성 주입 컨테이너 는 다음과 같은 점에서 다릅니다.

  • 의존성 주입은 더 나은 코드를 작성하는 방법입니다.
  • DI 컨테이너는 의존성 주입에 도움이되는 도구입니다.

의존성 주입을하기 위해 컨테이너가 필요하지 않습니다. 그러나 컨테이너가 도움이 될 수 있습니다.




DI (Dependency Injection) 란 무엇입니까?

다른 사람들이 말했듯이, DI (Dependency Injection) 는 우리의 관심 대상 (소비자 계층)이 ( UML 관점에서 ) 의존하는 다른 객체 인스턴스의 직접 작성 및 수명 관리의 책임을 제거합니다. 대신 이러한 인스턴스는 일반적으로 생성자 매개 변수 또는 속성 설정자를 통해 소비자 클래스에 전달됩니다 (종속 클래스 인스턴스의 관리 및 소비자 클래스 전달은 일반적으로 Inversion of Control (IoC) 컨테이너에서 수행되지만 다른 주제입니다) .

DI, DIP 및 SOLID

특히 로버트 C 마틴 (Robert C Martin)의 객체 지향 설계 (Object Oriented Design)SOLID 원칙의 패러다임에서 DI의존성 반전 원리 (Dependency Inversion Principle, DIP) 의 가능한 구현 중 하나이다. DIP은 SOLID mantra의 D 입니다. 다른 DIP 구현에는 Service Locator 및 Plugin 패턴이 포함됩니다.

DIP의 목적은 클래스 간의 긴밀하고 구체적인 의존 관계를 분리하고, 사용 된 언어와 접근 방식에 따라 interface , abstract class 또는 pure virtual class 를 통해 구현할 수있는 추상화를 통해 커플 링을 느슨하게하는 것입니다 .

DIP이 없다면, 우리의 코드 (이 '소비 클래스'라고 불렀습니다)는 구체적인 의존성에 직접 연결되어 있으며, 종종 이러한 의존성의 인스턴스를 얻고 관리하는 방법을 아는 책임이 있습니다 (개념적으로 :

"I need to create/use a Foo and invoke method `GetBar()`"

DIP를 적용한 후에 요구 사항이 느슨해지고 Foo 의존성의 수명을 얻고 관리하는 것에 대한 우려가 제거되었습니다.

"I need to invoke something which offers `GetBar()`"

DIP (및 DI)를 사용해야하는 이유는 무엇입니까?

이러한 방식으로 클래스 간의 종속성을 분리하면 이러한 종속성 클래스를 추상화의 전제 조건을 충족하는 다른 구현으로 쉽게 대체 할 수 있습니다 (예 : 종속성을 동일한 인터페이스의 다른 구현으로 전환 할 수 있음). 게다가 다른 사람들이 언급했듯이, 아마도 DIP를 통해 클래스들을 분리 하는 가장 일반적인 이유는 소비 클래스가 고립되어 테스트되도록 허용하는 것입니다. 왜냐하면 이러한 의존 관계가 이제는 스텁 및 / 또는 조롱 될 수 있기 때문입니다.

DI의 한 가지 결과는 종속성 객체가 생성자 또는 설정자 주입을 통해 소비 클래스로 전달되므로 종속 객체 인스턴스의 수명 관리가 소비 클래스에 의해 더 이상 제어되지 않는다는 것입니다.

다른 방법으로 볼 수 있습니다.

  • 소비 클래스에 의한 종속성의 수명 제어가 유지되어야하는 경우, 종속 클래스 인스턴스를 생성하기위한 추상 (abstract) 팩토리를 소비자 클래스에 주입하여 제어를 다시 설정할 수 있습니다. 소비자는 필요에 따라 공장에서 Create 를 통해 인스턴스를 얻을 수 있으며 완료되면 이러한 인스턴스를 처분 할 수 있습니다.
  • 또는 종속 인스턴스의 수명 제어를 IoC 컨테이너에 맡길 수 있습니다 (자세한 내용은 아래 참조).

DI를 언제 사용합니까?

  • 동등한 구현을 위해 의존성을 대체 할 필요가있을 경우,
  • 의존성을 분리하여 클래스의 메소드를 단위 테스트해야하는 경우 언제든지,
  • 의존성 수명의 불확실성이 실험을 보증 할 수있는 곳에서 (예, MyDepClass , MyDepClass 는 스레드 안전합니다 - 우리가 싱글 톤으로 만들고 모든 인스턴스에 동일한 인스턴스를 삽입한다면 어떨까요?)

다음은 간단한 C # 구현입니다. 주어진 소비 클래스 :

public class MyLogger
{
   public void LogRecord(string somethingToLog)
   {
      Console.WriteLine("{0:HH:mm:ss} - {1}", DateTime.Now, somethingToLog);
   }
}

겉으로보기에는 무해하지만, System.DateTimeSystem.Console 이라는 두 가지 클래스에 static 종속성이 두 가지 있습니다.이 클래스는 로깅 출력 옵션을 제한하지 않으며 (아무도보고 있지 않으면 콘솔 로깅은 쓸모가 없습니다.) 더 나쁘고 어렵습니다. 비 결정적 시스템 클럭에 대한 종속성을 자동으로 테스트합니다.

우리는이 클래스에 DIP 을 적용 할 수 있습니다. 타임 스탬프의 관심을 종속성으로 추상화하고 MyLogger 를 간단한 인터페이스에만 연결 MyLogger 됩니다.

public interface IClock
{
    DateTime Now { get; }
}

또한 Console 에 대한 종속성을 TextWriter 와 같은 추상화로 완화 할 수 있습니다. Dependency Injection은 일반적으로 constructor 삽입 (소비 클래스의 생성자에 대한 매개 변수로 추상화를 종속으로 전달) 또는 Setter Injection ( setXyz() setter 또는 .Net Property를 통해 종속성 전달)으로 setXyz() {set;} 한정된). 생성자 삽입은 클래스가 생성 된 후에 올바른 상태가되고 내부 종속성 필드가 readonly (C #) 또는 final (Java)으로 표시 될 수 있으므로 바람직합니다. 위 예제에서 생성자 삽입을 사용하면 다음과 같은 결과가 나옵니다.

public class MyLogger : ILogger // Others will depend on our logger.
{
    private readonly TextWriter _output;
    private readonly IClock _clock;

    // Dependencies are injected through the constructor
    public MyLogger(TextWriter stream, IClock clock)
    {
        _output = stream;
        _clock = clock;
    }

    public void LogRecord(string somethingToLog)
    {
        // We can now use our dependencies through the abstraction 
        // and without knowledge of the lifespans of the dependencies
        _output.Write("{0:yyyy-MM-dd HH:mm:ss} - {1}", _clock.Now, somethingToLog);
    }
}

(콘크리트 Clock 를 제공해야하며 당연히 DateTime.Now 돌아갈 수 있으며 두 종속성은 생성자 주입을 통해 IoC 컨테이너에서 제공해야합니다)

자동화 된 유닛 테스트를 빌드 할 수 있습니다.이 테스트는 로거가 올바르게 작동하고 있음을 증명합니다. 이제는 종속성에 대한 제어권을 갖게되었습니다. 시간, 그리고 우리는 작성된 출력을 감시 할 수 있습니다.

[Test]
public void LoggingMustRecordAllInformationAndStampTheTime()
{
    // Arrange
    var mockClock = new Mock<IClock>();
    mockClock.Setup(c => c.Now).Returns(new DateTime(2015, 4, 11, 12, 31, 45));
    var fakeConsole = new StringWriter();

    // Act
    new MyLogger(fakeConsole, mockClock.Object)
        .LogRecord("Foo");

    // Assert
    Assert.AreEqual("2015-04-11 12:31:45 - Foo", fakeConsole.ToString());
}

다음 단계

종속성 삽입은 항상 Inversion of Control 컨테이너 (IoC) 와 연관되어 있으며, 구체적인 종속 인스턴스를 주입 (제공)하고 수명 인스턴스를 관리합니다. 구성 / 부트 스트랩 프로세스 중에 IoC 컨테이너는 다음을 정의 할 수 있습니다.

  • 각 추상화와 구성된 구체화 구현 간의 매핑 (예 : "소비자가 IBar 요청하고 ConcreteBar 인스턴스를 반환 할 때" )
  • 각 소비자 인스턴스에 대해 새로운 객체를 생성하고, 모든 소비자에 대해 단일 종속성 인스턴스를 공유하고, 동일한 스레드에서만 동일한 종속성 인스턴스를 공유하는 등 각 종속성의 수명 관리를위한 정책을 설정할 수 있습니다.
  • .Net에서 IoC 컨테이너는 IDisposable 과 같은 프로토콜을 인식하고 구성된 수명 관리에 따라 종속성 삭제의 책임을 맡습니다.

일반적으로 IoC 컨테이너가 구성되고 / 부트 스트랩 된 후에는 백그라운드에서 원활하게 작동하여 코더가 의존성에 대해 걱정하지 않고 직접 코드에 집중할 수있게합니다.

DI 친화적 인 코드의 핵심은 클래스의 정적 결합을 방지하고 종속성 생성을 위해 new ()를 사용하지 않는 것입니다.

위의 예에서와 같이 종속성을 분리하려면 일부 디자인 작업이 필요하며 개발자에게는 new 종속성 습관을 직접적으로 파기하고 종속성을 관리하기 위해 컨테이너를 신뢰하는 패러다임 전환이 필요합니다.

그러나 혜택은 많은 것이고 특히 관심 분야를 철저히 테스트 할 수있는 능력에 있습니다.

참고 : POCO / POJO / Serialization DTO / Entity Graphs / Anonymous JSON 투영법 (예 : "데이터 전용"클래스 또는 레코드)의 생성 / 매핑 / 투영 ( new ..() 를 통해) 메소드에서 사용되거나 반환 된 메소드는 간주 되지 않습니다. (UML의 의미에서) 종속성으로 간주되며 DI가 적용되지 않습니다. new 프로젝트를 사용하면 이것만으로도 좋습니다.




DI (Dependency Injection)의 핵심은 애플리케이션 소스 코드를 깨끗 하고 안정적으로 유지하는 것입니다 .

  • 의존성 초기화 코드 정리
  • 의존성에 관계없이 안정 하다.

실질적으로 모든 디자인 패턴은 관심사를 분리하여 향후 변경 사항이 최소 파일에 영향을 미치도록 만듭니다.

DI의 특정 도메인은 종속성 구성 및 초기화의 위임입니다.

예 : 쉘 스크립트가있는 DI

자바 외부에서 일하는 경우 source가 종종 있는데, 많은 스크립팅 언어 (Shell, Tcl 등, 심지어 import는 Python에서 이러한 목적으로 오용 된 것) 에서 자주 사용되는 방법을 생각해보십시오 .

간단한 dependent.sh스크립트를 고려하십시오 .

#!/bin/sh
# Dependent
touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

스크립트는 종속적입니다. 자체적으로는 성공적으로 실행 archive_files되지 않습니다 (정의되지 않음).

구현 스크립트 archive_files에서 정의합니다 archive_files_zip.sh( zip이 경우 사용).

#!/bin/sh
# Dependency
function archive_files {
    zip files.zip "$@"
}

source종속 스크립트에서 구현 스크립트를 직접 실행 하는 대신 injector.sh"구성 요소"를 모두 포함 하는 "컨테이너"를 사용합니다 .

#!/bin/sh 
# Injector
source ./archive_files_zip.sh
source ./dependent.sh

archive_files 의존성 단지 한 주사따라 스크립트.

또는을 archive_files사용하여 구현 된 종속성을 주입 할 수 있습니다 .tarxz

예 : DI 제거

dependent.sh스크립트가 의존성을 직접 사용 했다면 , 그 접근법은 의존성 룩업 ( dependency lookup) 이라고 불리게 될 것입니다 ( 의존성 주입 과 반대입니다 ) :

#!/bin/sh
# Dependent

# dependency look-up
source ./archive_files_zip.sh

touch         "one.txt" "two.txt"
archive_files "one.txt" "two.txt"

이제 문제는 종속 "구성 요소"자체 초기화를 수행해야한다는 것입니다.

"component"소스 코드는 clean 이나 stable이 아니기 때문에 의존성 초기화의 모든 변경에는 "components"소스 코드 파일에 대한 새로운 릴리스가 필요하기 때문에 안정적이지 않습니다 .

마지막 말

DI는 Java 프레임 워크에서와 같이 크게 강조되고 대중화되지 않았습니다.

그러나 그것은 다음과 같은 우려를 나눌 수있는 일반적인 접근 방법입니다.

  • 응용 프로그램 개발 ( 단일 소스 코드 릴리스 수명주기)
  • 응용 프로그램 배포 ( 독립 실행 형 라이프 사이클이있는 여러 대상 환경)

종속성 조회 에서만 구성을 사용하면 종속성 (예 : 새 인증 유형) 및 지원되는 종속성 유형 (예 : 새 데이터베이스 유형)의 수만큼 구성 매개 변수 수가 변경 될 수 있으므로 도움이되지 않습니다.




내가 생각할 수있는 가장 좋은 비유는 외과의가 주된 사람인 수술실에서 외과의와 그의 조수 (들)가 필요하다면 외과의가 그 중 하나에 집중할 수 있도록 다양한 수술 구성 요소를 제공하는 조수이다. 그가 잘하는 일 (수술). 조수가 없으면 외과의 사는 그가 필요할 때마다 구성 요소를 스스로 가져야합니다.

DI는 간단히 말해서 종속 구성 요소를 가져 와서 구성 요소를 가져 오는 일반적인 추가 책임 (부담)을 제거하는 기술입니다.

DI는 당신과 같은 Single Responsibility (SR) 원칙에 가깝게 surgeon who can concentrate on surgery만듭니다.

DI 사용시기 : 거의 모든 생산 프로젝트 (소형 / 대형)에서 DI를 사용하는 것이 좋습니다 (특히 변화하는 비즈니스 환경에서).

이유 : 변경 사항을 신속하게 테스트하여 시장에 적용 할 수 있도록 코드를 쉽게 테스트하고 조롱 할 수 있기를 원합니다. 게다가 당신이 더 많은 컨트롤을 가지고있는 코드베이스로 여행 할 때 당신을 도와 줄 많은 훌륭한 무료 툴 / 프레임 워크가 없을 때, 왜 그렇게하지 않았을까요?




즉, 개체는 작업을 수행하는 데 필요한만큼의 종속성 만 가져야하며 종속성은 적어야합니다. 또한 객체의 종속성은 가능한 경우 "구체적인"객체가 아닌 인터페이스에 의존해야합니다. (구체적인 객체는 new라는 키워드로 생성 된 객체입니다.) 느슨한 결합은 재사용 가능성을 높이고 유지 관리가 쉬우 며 값 비싼 서비스 대신 "모의 (mock)"객체를 쉽게 제공 할 수있게합니다.

"Dependency Injection"(DI)은 "Inversion of Control"(IoC)이라고도 알려져 있으며이 느슨한 커플 링을 장려하는 기술로 사용될 수 있습니다.

DI 구현에는 두 가지 기본 접근 방식이 있습니다.

  1. 생성자 주입
  2. 세터 주입

생성자 주입

객체 의존성을 생성자에 전달하는 기술입니다.

생성자는 구체적인 객체가 아니라 인터페이스를 받아들입니다. 또한 orderDao 매개 변수가 null 인 경우 예외가 발생합니다. 이는 유효한 종속성을받는 것이 중요하다는 것을 강조합니다. 생성자 삽입은 객체에 의존성을 부여하기 위해 선호되는 메커니즘입니다. 개발자가 적절한 실행을 위해 "Person"객체에 의존성을 부여해야하는 객체를 호출하는 것은 명확합니다.

세터 주입

그러나 다음 예제를 고려해보십시오. 여러분이 의존성이없는 10 개의 메소드를 가진 클래스를 가지고 있다고 가정 해 봅시다. 그러나 IDAO에 의존성을 갖는 새로운 메소드를 추가하고 있습니다. Constructor Injection을 사용하도록 생성자를 변경할 수 있지만, 이로 인해 모든 생성자 호출이 변경 될 수 있습니다. 또는, 의존성을 취하는 새로운 생성자를 추가 할 수는 있지만 개발자가 한 생성자를 다른 생성자보다 더 쉽게 사용할 수있는 방법을 쉽게 알 수있는 방법은 무엇입니까? 마지막으로 의존성을 생성하는 데 비용이 많이 드는 경우, 생성되지 않고 생성자로 전달되는 것이 왜 드문 경우입니까? "Setter Injection"은 이와 같은 상황에서 사용할 수있는 또 다른 DI 기술입니다.

Setter Injection은 종속성을 생성자에 전달하도록 강제하지 않습니다. 대신 의존성은 필요한 객체에 의해 노출 된 public 속성으로 설정됩니다. 앞서 암시했듯이이를 수행하는 주요 동기는 다음과 같습니다.

  1. 레거시 클래스의 생성자를 수정하지 않고도 종속성 삽입을 지원합니다.
  2. 고비용의 자원이나 서비스가 필요할 때만 가능한 한 늦게 생성되도록 허용합니다.

다음은 위의 코드가 어떻게 생겼는지 보여주는 예입니다.

public class Person {
    public Person() {}

    public IDAO Address {
        set { addressdao = value; }
        get {
            if (addressdao == null)
              throw new MemberAccessException("addressdao" +
                             " has not been initialized");
            return addressdao;
        }
    }

    public Address GetAddress() {
       // ... code that uses the addressdao object
       // to fetch address details from the datasource ...
    }

    // Should not be called directly;
    // use the public property instead
    private IDAO addressdao;



Dependency Injection 은 코드의 한 부분 (예 : 클래스)이 하드 코딩되지 않고 모듈 방식으로 의존성 (코드의 다른 부분, 의존하는 부분)에 액세스 할 수 있는 방법을 의미합니다 (실제로는 어떤 방식 으로든 ). 필요에 따라 자유롭게 변경하거나 재정의 할 수 있으며 심지어 다른 시간에로드 할 수도 있습니다)

(그리고 추신 : 예, 그것은 오히려 단순한 컨셉에 대해 과장된 25 $ 이름이되었습니다) , 나의 .25센트




인기있는 대답은 도움이되지 않습니다. 왜냐하면 유용하지 않은 방식으로 의존성 주입을 정의하기 때문입니다. "의존성"이란 우리 객체 X가 필요로하는 기존의 다른 객체를 의미합니다. 하지만 우리가 말할 때 우리가 "의존성 주입"을한다고 말하지는 않습니다.

$foo = Foo->new($bar);

우리는 전달 인자를 생성자로 부릅니다. 우리는 생성자가 발명 된 이후로 정기적으로 그렇게 해왔습니다.

"종속성 주입"은 "제어 반전"의 한 유형으로 간주됩니다. 즉, 호출자에서 일부 논리가 제거됩니다. 호출자가 매개 변수를 전달하는 경우가 아니므로 DI 인 경우 DI는 제어 반전을 암시하지 않습니다.

DI는 호출자와 종속성을 관리하는 생성자 사이에 중간 수준이 있음을 의미합니다. Makefile은 의존성 주입의 간단한 예입니다. "호출자"는 명령 줄에서 "바 만들기"를 입력하는 사람이고 "생성자"는 컴파일러입니다. Makefile은 bar가 foo에 의존하고,

gcc -c foo.cpp; gcc -c bar.cpp

해보기 전에

gcc foo.o bar.o -o bar

bar를 타이핑하는 사람은 bar가 foo에 의존한다는 것을 알 필요가 없습니다. 의존성은 "make bar"와 gcc 사이에 주입되었습니다.

중간 수준의 주된 목적은 생성자에 의존성을 전달하는 것이 아니라 모든 종속성을 한 곳 에서 나열 하고 코더에서 숨길 수 있습니다 (코더가 제공하지 않도록).

일반적으로 중간 레벨은 생성 된 객체에 대한 팩토리를 제공하며, 요청 된 객체 유형이 만족해야하는 역할을 제공해야합니다. 중간 수준에서 건설의 세부 사항을 숨김으로써 공장에서 부여한 추상화 패널티가 이미 발생했기 때문에 공장을 사용할 수도 있습니다.




의존성 주입은 일반적으로 "종속성 난독 화 (Dependency Obfuscation)"요구 사항이라고 할 수있는 것에 대한 가능한 해결책 중 하나입니다. 종속성 (Dependency) 난독 화 (Obfuscation)는 클래스를 요구하는 클래스에 의존성을 제공하는 과정에서 '명백한'성질을 취하는 방식이며, 따라서 어떤면에서는 상기 클래스에 대한 종속성의 규정을 모호하게 만듭니다. 이것은 반드시 나쁜 것은 아닙니다. 실제로, 클래스에 의존성이 제공되는 방식을 모호하게함으로써, 클래스 외부의 것이 의존성 생성에 책임이있다. 이는 다양한 시나리오에서, 변경없이 종속성의 다른 구현이 클래스에 제공 될 수 있음을 의미한다 수업에. 이는 생산 및 테스트 모드 (예 : '모의 (mock)'서비스 의존성 사용) 사이를 전환 할 때 유용합니다.

불행히도 나쁜 부분은 어떤 사람들은 종속적 인 난독 화를하기위한 특수한 프레임 워크가 필요하다고 생각하고, 특정 프레임 워크를 사용하지 않기로 결정했다면 어떻게 든 '적은 프로그래머'라고 생각한다는 것입니다. 많은 사람들이 믿는, 매우 혼란스러운 신화는 의존성 주입이 의존성 난독 화를 달성하는 유일한 방법이라는 것입니다. 이것은 명백하게 역사적으로나 분명히 100 % 잘못되었지만 종속성 주입 난독 처리 요구 사항에 대한 의존성 주입에 대한 대안이 있다는 것을 사람들에게 납득시키는 데 어려움을 겪을 것입니다.

프로그래머는 수년간 의존성 난독 화 요구 사항을 이해했으며 많은 대안 솔루션이 종속성 주입이 생각되기 전과 후에 진화했습니다. Factory 패턴이 있지만 ThreadLocal을 사용하는 많은 옵션이 있는데, 특정 인스턴스에 대한 주입이 필요하지 않습니다. 종속성은 스레드에 효과적으로 주입되어 객체를 (편리한 정적 getter 메소드를 통해) 모든 객체에 사용 가능하게 만듭니다.그것을 필요로하는 클래스에 어노테이션을 추가 할 필요없이 복잡한 XML '아교 (glue)'를 설정하지 않아도 필요한 클래스입니다. 의존성이 영속성 (JPA / JDO 또는 무엇이든)을 위해 필요할 때, 도메인 모델과 비즈니스 모델 클래스가 순전히 POJO (즉, 특정 프레임 워크에 한정되거나 주석에 고정되지 않은)로 이루어진 'tranaparent persistence'를 훨씬 쉽게 얻을 수 있습니다.




Apress.Spring.Persistence.with.Hibernate.Oct.2010에서

종속성 주입의 목적은 외부 소프트웨어 구성 요소를 응용 프로그램 비즈니스 논리에서 분리하는 작업을 분리하는 것입니다. 종속성 삽입없이 구성 요소가 필요한 서비스에 액세스하는 방법에 대한 세부 정보는 구성 요소 코드로 혼란 스러울 수 있습니다. 이렇게하면 오류 가능성이 증가하고 코드가 부풀어 오르고 유지 관리 복잡성이 커집니다. 구성 요소를 더 가깝게 연결하기 때문에 리팩토링 또는 테스트시 종속성을 수정하기가 어렵습니다.




간단히 말해서, 의존성 삽입 (Dependency Injection, DI)은 서로 다른 객체 간의 종속성 또는 밀접한 결합을 제거하는 방법입니다. Dependency Injection은 각 객체에 응집력있는 동작을 제공합니다.

DI는 Spring의 IOC principal의 구현입니다. "우리에게 전화하지 마라."라고 적혀 있습니다. 의존성 삽입 프로그래머는 new 키워드를 사용하여 객체를 생성 할 필요가 없습니다.

객체는 일단 Spring 컨테이너에로드 된 다음 getBean (String beanName) 메소드를 사용하여 Spring 컨테이너에서 객체를 가져 와서 필요할 때마다 다시 사용합니다.




DI (Dependency Injection)는 Inversion of Control (IoC)이라고도하는 Dependency Inversion Principle (DIP)의 일부입니다. 기본적으로 하나의 모 놀리 식 시스템 대신 코드를 모듈화하고 단위 테스트 할 수 있기를 원하기 때문에 DIP을 수행해야합니다. 따라서 클래스에서 분리되어 추상화 된 코드 부분을 식별하기 시작합니다. 이제 추상화 구현은 클래스 외부에서 주입해야합니다. 일반적으로 이것은 생성자를 통해 수행 할 수 있습니다. 그래서 추상화를 매개 변수로 받아들이는 생성자를 생성합니다. 이것은 생성자를 통해 종속성 주입이라고합니다. DIP, DI 및 IoC 컨테이너에 대한 자세한 설명은 Here




나는 의존성 주입이 무엇인지에 대해 약간 다른, 짧고 정확한 정의를 제안 할 것인데, 기술적 인 수단이 아니라 here 에서 here 입니다.

Dependency Injection은 각 서비스가 의존성에 의해 매개 변수화 된 서비스 객체의 정적 인 상태 비 저장 그래프를 만드는 프로세스입니다.

Java, C # 또는 다른 객체 지향 언어를 사용하더라도 관계없이 응용 프로그램에서 만드는 객체는 일반적으로 다음과 같은 두 가지 범주 중 하나입니다. 상태 비 저장 정적 및 전역 "서비스 객체"(모듈) 및 상태 저장 동적 및 로컬 "데이터 개체".

모듈 그래프 - 서비스 개체의 그래프 -은 일반적으로 응용 프로그램 시작시 만들어집니다. 이것은 Spring과 같은 컨테이너를 사용하여 수행 할 수 있지만 매개 변수를 객체 생성자에 전달하여 수동으로 수행 할 수도 있습니다. 두 가지 방법 모두 장점과 단점이 있지만 응용 프로그램에서 DI를 사용하기위한 틀은 틀림없이 꼭 필요한 것은 아닙니다.

하나의 요구 사항은 서비스가 종속성에 의해 매개 변수화되어야한다는 것입니다. 이것이 의미하는 바는 주어진 시스템에서 취한 언어와 접근 방식에 따라 달라집니다. 일반적으로 이것은 생성자 매개 변수의 형태를 취하지 만 설정자를 사용하는 것도 옵션입니다. 이는 또한 서비스 사용자의 서비스 종속성이 (서비스 메소드 호출시) 숨겨 짐을 의미합니다.

언제 사용합니까? 모듈간에 의존성 그래프를 사용하여 논리를 다른 모듈로 캡슐화하는 데 필요한 응용 프로그램이 충분히 클 때마다 코드의 가독성과 탐색 가능성이 향상됩니다.




Related