[dependency-injection] 제어의 반전 대 의존성 주입

Martin Fowler가 작성한 논문 에 따르면 제어의 반전은 프로그램의 제어 흐름이 반전되는 원리입니다. 프로그래머가 프로그램의 흐름을 제어하는 ​​대신 외부 소스 (프레임 워크, 서비스, 기타 구성 요소)가 그것. 마치 무언가를 다른 것에 연결하는 것과 같습니다. 그는 EJB 2.0에 대한 예를 언급했습니다.

예를 들어 Session Bean 인터페이스는 ejbRemove, ejbPassivate (보조 스토리지에 저장 됨) 및 ejbActivate (패시브 상태에서 복원 됨)를 정의합니다. 이러한 메소드가 호출되는 시점을 제어 할 수 없으며 수행 방식 만 수행 할 수 있습니다. 컨테이너는 우리를 부르고 우리는 부르지 않습니다.

이는 프레임 워크와 라이브러리의 차이점으로 이어집니다.

제어의 반전은 프레임 워크를 라이브러리와 다르게 만드는 주요 부분입니다. 라이브러리는 본질적으로 호출 할 수있는 함수 세트이며, 요즘에는 대개 클래스로 구성됩니다. 각 호출은 일부 작업을 수행하고 클라이언트에게 제어권을 반환합니다.

DI가 IOC라는 관점은 객체의 종속성이 반전된다는 것을 의미합니다. 자체 종속성, 수명주기를 제어하는 ​​대신 다른 무언가가 당신을 위해 그것을합니다. 그러나 DI에 대해 직접 말했듯이 DI는 반드시 IOC 일 필요는 없습니다. 우리는 여전히 DI와 IOC를 가질 수 없습니다.

그러나이 백서 (C / C ++의 또 다른 IOC 프레임 워크 인 pococapsule에서)는 IOC와 DI 때문에 I2 컨테이너와 DI 프레임 워크가 J2EE보다 훨씬 우수하다는 것을 제안합니다. 따라서 POJO / POCO (Plain Old Java / C ++ Object)로 만들지 않습니다.

종속성 주입 패턴 이외의 제어 컨테이너 반전 (아카이브 링크)

이전의 컴포넌트 기반 개발 프레임 워크의 문제점을 이해하기위한 추가 자료, 위의 두 번째 논문 : 제어의 반전 이유 및 이유 (아카이브 링크)

내 질문 : IOC와 DI는 정확히 무엇입니까? 혼란 스러워요. pococapsule을 기반으로 IOC는 객체 또는 프로그래머와 프레임 워크 간의 제어를 뒤집는 것보다 더 중요한 것입니다.



답변

IoC 는 애플리케이션이 프레임 워크에서 메소드를 호출하는 것이 아니라 일반적인 용어의 의미이며, 프레임 워크는 애플리케이션이 제공하는 구현을 호출합니다.

DI 는 IoC의 한 형태로, 구현은 생성자 / 설정자 / 서비스 조회를 통해 객체로 전달되며, 객체는 올바르게 동작하기 위해 ‘종속’됩니다.

DI를 사용하지 않는 IoC 는 구현이 서브 클래 싱을 통해서만 변경 될 수 있기 때문에 템플릿 패턴이됩니다.

DI 프레임 워크DI 를 사용하도록 설계되었으며 구현에 쉽게 전달할 수 있도록 인터페이스 (또는 Java의 주석)를 정의 할 수 있습니다.

IoC 컨테이너 는 프로그래밍 언어 외부에서 작동 할 수있는 DI 프레임 워크입니다. 일부는 덜 침입적인 메타 데이터 파일 (예 : XML)에 사용할 구현을 구성 할 수 있습니다. 일부에서는 pointcuts에 구현을 주입하는 것과 같이 일반적으로 불가능한 IoC를 수행 할 수 있습니다 .

Martin Fowler의 기사도 참조하십시오 .


답변

요컨대, IoC는 DI를 포함하지만 이에 국한되지 않는 훨씬 광범위한 용어입니다.

IoC (Inversion of Control)라는 용어는 원래 전체 프레임 워크 또는 런타임이 프로그램 흐름을 제어하는 ​​모든 종류의 프로그래밍 스타일을 의미했습니다.

DI가 이름을 갖기 전에 사람들은 종속성을 제어 컨테이너의 반전으로 관리하는 프레임 워크를 참조하기 시작했으며 곧 IoC의 의미가 점차 특정 의미 인 종속성에 대한 제어의 반전으로 바뀌 었습니다.

IoC ( Inversion of Control )는 개체가 작업에 의존하는 다른 개체를 만들지 않음을 의미합니다. 대신 외부 소스 (예 : xml 구성 파일)에서 필요한 객체를 가져옵니다.

DI ( Dependency Injection )는 일반적으로 생성자 매개 변수를 전달하고 속성을 설정하는 프레임 워크 구성 요소에 의해 개체 개입없이 수행됩니다.


답변

여기에 이미지 설명을 입력하십시오
출처

IoC ( I nversion o f C ontrol) :-일반적인 용어이며 여러 가지 방법 (이벤트, 델리게이트 등)으로 구현됩니다.

DI ( D ependency I njection) – DI는 IOC는의 서브 타입에 의해 구현되는 생성자 주입 세터 주사 또는 주입 인터페이스 .

그러나 Spring은 다음 두 가지 유형 만 지원합니다.

  • 세터 주입
    • Setter 기반 DI는 인수 없음 생성자 또는 인수 없음 정적 팩토리 메소드를 호출하여 Bean을 인스턴스화 한 후 사용자 Bean에서 setter 메소드를 호출하여 실현됩니다.
  • 생성자 주입
    • 생성자 기반 DI는 각각 공동 작업자를 나타내는 여러 인수로 생성자를 호출하여 구현됩니다.이를 사용하여 삽입 된 Bean이 널이 아니고 빠르게 실패하는지 (컴파일 시간에 실패하고 런타임에 실패) 유효성을 검증 할 수 있습니다. 응용 프로그램 자체를 시작하는 동안 우리는 얻을 수 NullPointerException: bean does not exist있습니다. 생성자 주입은 종속성을 주입하는 가장 좋은 방법입니다.

답변

DI는 IoC의 하위 집합입니다

  • IoC 는 객체가 자신의 작업에 의존하는 다른 객체를 생성하지 않음을 의미합니다. 대신 외부 서비스 (예 : xml 파일 또는 단일 앱 서비스)에서 필요한 개체를 가져옵니다. 내가 사용하는 IoC의 두 가지 구현은 DI와 ServiceLocator입니다.
  • DI 는 구체적인 객체를 사용하지 않고 추상화 (인터페이스)를 사용하지 않고 종속 객체를 얻는 IoC 원칙을 의미합니다. 이렇게하면 모든 구성 요소 체인을 테스트 할 수 있으며, 상위 구성 요소는 하위 수준 구성 요소에 의존하지 않고 인터페이스에서만 가능합니다. Mocks는 이러한 인터페이스를 구현합니다.

다음은 IoC를 달성하기위한 다른 기술들 입니다.


답변

모든 대답이 이론을 강조하기 때문에 첫 번째 접근법의 예를 보여 드리겠습니다.

주문이 배송되면 SMS 확인 메시지를 보내는 기능이 포함 된 응용 프로그램을 구축한다고 가정합니다. 우리는 두 가지 클래스를 가질 것입니다. 하나는 SMS (SMSService)를 전송하고 다른 하나는 사용자 입력 (UIHandler)을 캡처해야합니다. 코드는 다음과 같습니다.

public class SMSService
{
    public void SendSMS(string mobileNumber, string body)
    {
        SendSMSUsingGateway(mobileNumber, body);
    }

    private void SendSMSUsingGateway(string mobileNumber, string body)
    {
        /*implementation for sending SMS using gateway*/
    }
}

public class UIHandler
{
    public void SendConfirmationMsg(string mobileNumber)
    {
        SMSService _SMSService = new SMSService();
        _SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!");
    }
}

위의 구현은 잘못된 것이 아니지만 몇 가지 문제가 있습니다
.-) 개발 환경에서 SMS 게이트웨이를 사용하는 대신 텍스트 파일로 전송 된 SMS를 저장하여이를 달성하려고합니다. 다른 구현으로 (SMSService)의 구체적인 구현을 변경하면 유연성이 떨어지고이 경우 코드를 다시 작성해야합니다.
-) 클래스의 혼합 책임을 끝내고, (UIHandler)는 (SMSService)의 구체적인 구현에 대해 절대 알 수 없어야합니다. 이는 “인터페이스”를 사용하여 클래스 외부에서 수행해야합니다. 이것이 구현되면 동일한 인터페이스를 구현하는 다른 모의 서비스와 함께 사용되는 (SMSService)를 교체하여 시스템의 동작을 변경할 수 있습니다.이 서비스는 mobileNumber로 전송하는 대신 SMS를 텍스트 파일로 저장합니다.

위의 문제를 해결하기 위해 우리는 우리의 (SMSService) 및 새로운 (MockSMSService)에 의해 구현되는 인터페이스를 사용합니다. 기본적으로 새로운 인터페이스 (ISMSService)는 아래 코드와 동일한 서비스 동작을 노출합니다.

public interface ISMSService
{
    void SendSMS(string phoneNumber, string body);
}

그런 다음 (SMSService) 인터페이스를 구현하기 위해 (SMSService) 구현을 변경합니다.

public class SMSService : ISMSService
{
    public void SendSMS(string mobileNumber, string body)
    {
        SendSMSUsingGateway(mobileNumber, body);
    }

    private void SendSMSUsingGateway(string mobileNumber, string body)
    {
        /*implementation for sending SMS using gateway*/
        Console.WriteLine("Sending SMS using gateway to mobile:
        {0}. SMS body: {1}", mobileNumber, body);
    }
}

이제 동일한 인터페이스를 사용하여 완전히 다른 구현으로 새로운 목업 서비스 (MockSMSService)를 만들 수 있습니다.

public class MockSMSService :ISMSService
{
    public void SendSMS(string phoneNumber, string body)
    {
        SaveSMSToFile(phoneNumber,body);
    }

    private void SaveSMSToFile(string mobileNumber, string body)
    {
        /*implementation for saving SMS to a file*/
        Console.WriteLine("Mocking SMS using file to mobile:
        {0}. SMS body: {1}", mobileNumber, body);
    }
}

이 시점에서 아래와 같이 (UIHandler)의 코드를 변경하여 구체적인 서비스 구현 (MockSMSService)을 쉽게 사용할 수 있습니다.

public class UIHandler
{
    public void SendConfirmationMsg(string mobileNumber)
    {
        ISMSService _SMSService = new MockSMSService();
        _SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!");
    }
}

우리는 코드에서 많은 유연성을 달성하고 코드 분리 문제를 구현했지만 두 SMS 서비스 간을 전환하려면 코드베이스를 변경해야합니다. 따라서 Dependency Injection 을 구현해야합니다 .

이를 위해서는 (UIHandler) 클래스 생성자에 대한 변경 사항을 구현하여 종속성을 전달해야합니다. 이렇게하면 (UIHandler)를 사용하는 코드가 (ISMSService)의 구체적인 구현을 결정할 수 있습니다.

public class UIHandler
{
    private readonly ISMSService _SMSService;

    public UIHandler(ISMSService SMSService)
    {
        _SMSService = SMSService;
    }

    public void SendConfirmationMsg(string mobileNumber)
    {
        _SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!");
    }
}

이제 클래스 (UIHandler)와 통신 할 UI 양식은 사용할 인터페이스 구현 (ISMSService)을 전달해야합니다. 이것은 우리가 컨트롤을 뒤집 었음을 의미합니다. (UIHandler)는 더 이상 사용할 구현을 결정할 책임이 없으며 호출 코드는 수행합니다. DI가 그것의 한 유형 인 Inversion of Control 원리를 구현 했습니다.

UI 폼 코드는 다음과 같습니다.

class Program
{
    static void Main(string[] args)
    {
        ISMSService _SMSService = new MockSMSService(); // dependency

        UIHandler _UIHandler = new UIHandler(_SMSService);
        _UIHandler.SendConfirmationMsg("96279544480");

        Console.ReadLine();
    }
}


답변

IOC (Inversion Of Control) : 객체의 인스턴스를 얻기 위해 컨테이너에 제어 권한을 부여하는 것을 제어의 반전이라고합니다. 새로운 연산자를 사용하여 객체를 생성하는 대신 컨테이너가 자동으로 처리하도록하십시오.

DI (종속 주입) : 객체에 속성을 주입하는 방법을 의존성 주입 이라고 합니다.

의존성 주입 에는 세 가지 유형이 있습니다 .

  1. 생성자 주입
  2. 세터 / 게터 주입
  3. 인터페이스 주입

Spring은 Constructor InjectionSetter / Getter Injection 만 지원합니다 .


답변

그러나 스프링 문서는 동일하다고 말합니다.

http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-introduction

첫 번째 줄에서 ” IoC는 의존성 주입 (DI)으로도 알려져 있습니다.