DI 보충자료

DI(Dependency Injection, 의존성 주입)

1. DI란 무엇인가?

**DI(Dependency Injection)**는 객체가 협력하는 데 필요한 의존성을 직접 생성하지 않고, 외부에서 주입받는 설계 패턴입니다. DI는 객체 간의 결합도를 줄이고 코드의 유연성을 높이며, IoC(Inversion of Control)를 구현하는 가장 일반적인 방법 중 하나로 사용됩니다.


2. DI의 기본 개념

전통적인 방식

  • 객체가 자신의 의존성을 직접 생성합니다.

  • 예: Car 클래스가 Engine 객체를 직접 생성하여 사용.

    public class Car {
        private Engine engine;
    
        public Car() {
            this.engine = new Engine(); // 직접 생성
        }
    }

DI 방식

  • 객체는 자신의 의존성을 외부에서 주입받아 사용합니다.

  • 객체는 구체적인 구현에 의존하지 않고, 인터페이스 또는 추상 클래스에 의존함으로써 유연성을 확보합니다.

    public class Car {
        private Engine engine;
    
        public Car(Engine engine) { // 의존성 주입
            this.engine = engine;
        }
    }

3. DI의 주입 방법

DI는 의존성을 객체에 주입하는 여러 가지 방식을 제공합니다. 각 방식은 상황에 따라 적절하게 사용됩니다.

1. 생성자 주입 (Constructor Injection)

  • 생성자를 통해 의존성을 주입받는 방식입니다.

  • 장점:

    • 객체 생성 시 의존성을 반드시 주입받도록 강제할 수 있음.

    • 불변성을 보장.

    public class Car {
        private final Engine engine;
    
        public Car(Engine engine) { // 생성자 주입
            this.engine = engine;
        }
    }

2. 세터 주입 (Setter Injection)

  • Setter 메서드를 통해 의존성을 주입받는 방식입니다.

  • 장점:

    • 선택적인 의존성을 주입 가능.

    • 객체 생성 후 의존성을 주입받을 수 있음.

    public class Car {
        private Engine engine;
    
        public void setEngine(Engine engine) { // 세터 주입
            this.engine = engine;
        }
    }

3. 필드 주입 (Field Injection)

  • 필드에 직접 주입하는 방식으로, 주로 프레임워크에서 자동으로 처리됩니다.

  • 단점:

    • 테스트 시 Mock 객체 주입이 어려움.

    public class Car {
        @Autowired
        private Engine engine; // 필드 주입
    }

4. DI의 장점

1. 유연성 향상

  • 객체 간의 결합도를 줄이고, 코드 변경 없이도 의존 객체를 쉽게 교체 가능.

  • 새로운 구현체로 변경할 때, 주입만 수정하면 되므로 기존 코드를 최소한으로 수정.

2. 테스트 용이

  • DI를 사용하면 의존성을 Mock 객체로 교체하여 단위 테스트를 쉽게 수행할 수 있습니다.

  • 예: Car 객체를 테스트할 때, 실제 Engine 객체 대신 테스트용 MockEngine 객체를 주입.

3. 재사용성 향상

  • 객체가 구체적인 구현 대신 인터페이스에 의존하므로, 다양한 구현체를 주입하여 코드 재사용성을 높임.

4. 확장성 확보

  • 코드 변경 없이도 새로운 기능이나 의존성을 쉽게 추가할 수 있습니다.


5. DI와 IoC의 관계

  • DI는 IoC를 구현하는 가장 대표적인 방법입니다.

  • IoC는 객체 생성 및 의존성 관리를 개발자가 아닌 외부 컨테이너가 처리하는 개념이고, DI는 이를 실현하는 구체적인 방식입니다.


6. DI의 실제 적용: 스프링 프레임워크

1. 생성자 주입 예제

@Component
public class Engine {
}

@Component
public class Car {
    private final Engine engine;

    @Autowired
    public Car(Engine engine) { // 생성자 주입
        this.engine = engine;
    }
}

2. 세터 주입 예제

@Component
public class Car {
    private Engine engine;

    @Autowired
    public void setEngine(Engine engine) { // 세터 주입
        this.engine = engine;
    }
}

7. DI의 활용 사례

  • Spring Framework: 스프링은 DI를 활용하여 의존성을 관리하고 객체를 주입.

  • JUnit 테스트: DI를 통해 Mock 객체를 주입하여 테스트를 쉽게 작성.

Last updated