[TIL] DI와 DI 컨테이너

muchan
muchan
∙∙조회 8

개요

우리가 흔히 싱글톤으로 관리하는 코드는 편리하지만 몇가지 문제가 있다

  • 숨은 종속성: 필드, 시그니처만 봐선 의존이 안보이고 .Instance가 본문 깊은 곳에 숨음
  • 스트 곤란: 전역 정적 상태라 로직만 검증하고 시어도 진짜 매니저가 필요
  • 높은 결합도: 구체 클래스에 직접 묶여 구현 교체, 다른 프로젝트 재사용이 어려움

"하나뿐"은 살리고 전역 접근만 걷어내고자 DI와 DI컨테이너 사용

싱글턴 분석

csharp
// 싱글턴 수업에서 배운 고전 형태
public class GameManager : MonoBehaviour
{
    public static GameManager Instance { get; private set; }   // ① 전역 정적 접근

    private void Awake()
    {
        // 같은 매니저를 담은 씬을 다시 로드하면 두 번째가 생긴다 → 이 가드로 지움(안티패턴의 증상)
        if (Instance != null && Instance != this) { Destroy(gameObject); return; }

        Instance = this;
        DontDestroyOnLoad(gameObject);                          // ② 씬을 넘어 생존
    }
}
묶인 특성무엇인가DI는 무엇으로 대체하나
① 전역 정적 접근(.Instance)어디서나 끌어다 쓰는 접근/가시성주입: 의존을 시그니처로 받음(3·5절)
② 씬 생존(DontDestroyOnLoad)씬을 넘어 사는 수명/스코프Root LifetimeScope의 Singleton 수명(3차시)

핵심은 필요한 의존을 전역에서 꺼내(pull)쓰지 않고, 어떻게 밖에서 건네받게(push)할까?


DI의 정의

Dependency Injection: 가져오기(pull)을 건네받기(push)로 뒤집는 것
객체가 필요한 의존을 스스로 찾지 않고 밖에서 건네 받음(주입)

new, .Instance, FindObjectOfType, GameObject.Find, GetComponent로 씬을 뒤져 캐싱 = pull

[SerializeField] 인스펙터 드래그 = push

DIP(원칙)와 DI(기법)

DIP는 SOLID에 종속성 역전 원칙 "구체가 아니라 추상화에 의존하라"
DI는 그 원칙을 코드로 실현하는 기법 "어느 방향으로 의존해야 하는가"

순수 DI와 조립 지점

  • 1단계: 추상화 추출
  • 2단계: 의존을 주입받기
  • 3단계: 조립 지점에서 손 조립

한계

  • 조립 코드 비대화
  • 수명 관리 수동
  • 실행 루프 연결 수동
  • 씬 경계 전달 번거로움

DI 컨테이너

조립 지점의 수작업을 자동화하는 라이브러리. 어떤 컨테이너든 핵심은 다음 세 동작

동작답하는 질문컨테이너가 하는 일
등록(Register)무엇을, 어떤 수명으로?“IAudioService가 필요하면 AudioManager를 줘라” 같은 조립 규칙을 한곳에 모아 둠
해석(Resolve)이 타입 하나 줘생성자 시그니처를 분석해 필요한 의존을 재귀적으로 만들어 끼움, 그래프 자동 조립
수명(Lifetime)몇 개나, 언제까지?하나를 공유할지 매번 새로 만들지 결정하고, 스코프가 끝나면 Dispose까지 관리