본문 바로가기
- CS/OOP

[CS] DI Dependency Injection

by david_동근 2025. 6. 23.

디펜던시 인젝션, 우리말로 '의존성 주입'인데

저는 어감 때문에 처음엔 조금 낯설게 느껴졌습니다.

 


 

DI; Dependency Injection

Dependency Injection(의존성 주입)을 프로그래밍 차원에서는

클래스가 필요한 객체(의존성)를 스스로 생성하지 않고, 외부에서 주입받는 방식을 말합니다.

 

먼저 Dependency(의존성)는, "A depends on B." ("A가 B에 의존한다.") 관계 입니다.

그렇기 때문에, 의존대상인 B가 변한다면 → A에게도 영향이 갈 것입니다.

예를 들어 자동차와 엔진으로 비유해서 설명드리자면,

Car는 Engine 없이 작동할 수 없으니까, Car는 Engine에 의존하는 것을 Dependency (의존성)이라고 합니다.

원래는 Car가 스스로 직접 Engine 객체를 생성하고 있었지만,

대신에 외부 (DI 컨테이너)가 Engine 객체를 생성해서 Car에게 전달하는 것을 DI (의존성 주입)이라고 합니다.

 

다르게 말하면, Coupling (결합도) 를 최소화하기 위한 작업이라고 볼 수 있습니다.

 

아래 예시 코드를 보겠습니다.

class Car {
	private Engine engine;
    
    public Car() {
    	engine = new Engine();
    }
}

 

Car가 Engine 객체를 스스로 직접 생성하므로, '강하게 결합' 됩니다.

즉, Engine을 (e.g. ElectricEngine으로)변경하면 Car도 함께 수정해줘야 합니다.

 

이번엔 DI 개념을 사용하여 코드를 작성하자면,

public class Car {
	private readonly Engine engine; // 요 engine이 아래 5번줄 this.engine 이에용
    
    public Car(Engine engine) {
    	this.engine = engine; // 외부에서 필요한 의존성을 전달 받아용
    }
}

 

Car 는 Engine 을 생성하지 않으므로 '느슨하게 결합' 됩니다.

그렇기 때문에 다른 종류의 Engine (e.g. GasEngine, ElectricEngine 등...) 도 쉽게 교체할 수 있습니다.

(객체를 생성하는 부분과 로직이 분리 돼있고, Mock 객체를 사용해서 Unit Test 에도 용이해요)

 

Interface 추상화

DI 의 핵심 원칙은 바로, Concrete (구체, 구현) 클래스 대신 Interface 에 의존하는 것입니다.

(이를 읜존성 역전 원칙, DIP 라고 합니다. 해당 내용은 아래 포스트에 정리해뒀어용 https://bulletprooves.tistory.com/67)

 

[OOP] SOLID 설계 원칙

Solid 해서 생각난 이야기에용SOLID that's so slippery?얼음이 미끄럽단 건 삼척동자도 압니다. 하지만, 왜?they say, in the case of ice, that when you stand on it.momentarily the pressure melts the ice a little bit (미끄덩)so yo

bulletprooves.tistory.com

 

이번엔, Interface로 추상화를 통해, 다양한 Engine 들을 의존 받을 수 있게 만들어보겠습니다.

(인터페이스에 대해서는 아래 포스트에 정리해두었습니당 https://bulletprooves.tistory.com/36)

 

[C#] virtual abstract interface

OOP에서 상속에 관한 키워드 virtual(추상), abstract(가상) 한정자와 interface를 정리했습니다.세가지 키워드 모두 Override(재정의) 할 수 있다는 공통점이 있지만, 사용 방식과 목적에 차이가 있습니다.

bulletprooves.tistory.com

public interface IEngine { // 인터페이스로 구현만 하고, 다양한 모양의 클래스로 (다중 상속) 하게 해용
	void Start();
}

public class ElectroEngine : IEngine {
	public void Start() => Console.WriteLine("딩동! 우우웅~");
}

public class GasEngine : IEngine {
	public void Start() => Console.WriteLine("찰칵! 부릉부릉!");
}

// 아래 Car는 IEngine 인터페이스에만 의존하게 되죵
public class Car {
	private readonly IEngine _engine;
    
    public Car (IEngine eng) {
    	_engine = eng;
    }
    
    public void Start() {
    	_engine.Start();
    }
}

 

DI 는 위처럼,

생성자를 통해 전달(주입) 하거나

public class Car {
    private readonly IEngine _engine;

    public Car(IEngine engine) {
        _engine = engine;
    }
}

 

속성을 통해 전달(주입) 하거나

public class Car {
    public IEngine Engine { get; set; }
}

 

메서드 파라미터를 통해 전달(주입)이 가능합니다.

public void TestDrive(IEngine engine) {
    engine.Start();
}

 

DI 를 사용했을 때의 장점?

의존 관계를 분리해 위와 같이 주입 받게되면,

의존하는 부분이 Interface로 추상화되어 변경과 확장에 용이하단 점과,

Mocking 이 가능해 Unit Test (단위 테스트)가 쉬워지며,

코드 재사용성과 가독성이 높아지는 장점이 있습니다.


 

미루다 미루다 드디어 정리하게 됐네용.

다음 포스트에선 Unity의 VContainer에 대해 정리하겠습니당.

그럼 오늘도 행복한 하루 되세요~ (๑˃́ꇴ˂̀๑)

참고 : https://tecoble.techcourse.co.kr/post/2021-04-27-dependency-injection/

'- CS > OOP' 카테고리의 다른 글

[OOP] OOP Object-Oriented Programming 개요  (1) 2025.06.07
[OOP] SOLID 설계 원칙  (2) 2025.06.07
[OOP] Design Patterns ( GoF )  (0) 2025.05.26