- 의존성과 관련해서 글을 찾아보면 Ioc, DIP, DI, Ioc Container란 용어가 나온다. 언뜻 보면 다 비슷해보이는 용어라 헷갈려보인다. 그래서 한 사이트의 도움을 빌려 정리해보기로 했다.

■ 용어 정리

- IoC : Inversion of Control (제어 역전)

- DIP : Dependency Inversion Principle (의존 역전 원칙),

- DI : Dependency Injection (의존성 주입)

- Ioc : Ioc Container

■ 분류


설계 원칙

IoC (Inversion of Control)

DIP (Dependency Inversion Principle)

디자인 패턴

DI (Dependency Injection)

프레임워크

Ioc Container

- IoC랑 DIP는 설계 원칙(Design Principle)에 해당되고 DI는 디자인 패턴(Design Pattern), IoC는 프레임워크에 해당된다.

- Design Principle과 " Pattern은 언뜻 보기에 헷갈려보인다.

Design Principle은 하이레벨 차원에서 프로그램을 더 좋게 설계하기 위한 가이드라인이고, 그렇기에 Design Principle은 구현 방법을 제공하진 않고 어느 언어에도 종속되지 않는다. 잘 알려진 예로는 객체지향 설계 5대 원칙이라 불리는 SOLID 원칙이 대표적이다.

반면 Design Pattern은 로우레벨 차원에서 객체지향을 구현하는 데 일반적으로 발생하는 문제를 해결하기 위한 방법이다. 대표적인 예로는 싱글톤 패턴, 팩토리 패턴, 커맨드 패턴이 있다.

■ IoC

- IoC(제어 역전 : Inversion of Control)는 객체지향 설계에서 클래스 간 의존성을 줄이기 위해 제어를 역전시키는 데 사용하는 설계원칙이다. 여기서 제어란 한 클래스가 가진 주요 책임 외에 가진 다른 부가적인 책임을 이르는 말로, 이 뜻은 프로그램의 흐름에 관한 제어나 객체 생성과 의존 객체 생성 및 연결에 관한 제어도 포함된다.

- IoC는 제어를 역전시키기 위한 방법론이다. 비전문가의 말을 빌려 설명해보자면 이렇다. 한번 예를 들어 당신이 차를 타고 직장으로 간다고 해보자. 여기에서 당신은 차에 대한 제어를 가지고 있으며 IoC는 이 상황에서 제어를 역전시키라고 제안한다. 당신이 직접 차를 모는 대신, 기사를 고용해 기사가 제어를 가지도록 하는 것이다. 이것이 바로 제어 역전이다. 이러면 당신은 차를 직접 몰지 않고 기사에게 시켜서 당신의 본래 일에 집중할 수 있게 된다.

이런 식으로 IoC 설계 원칙을 적용하면 클래스 간 의존성을 줄여서 프로젝트를 테스트하고 관리하고 확장하는 데 용이하게 될 것이다.

■ DIP

- DIP는 객체지향 5대 원칙이라 불리는 SOLID 원칙 중 하나인 '설계 역전 원칙'으로 그 내용은 다음과 같다.

- 1. 하이 레벨에 있는 모듈은 로우 레벨에 있는 모듈에 의존적이면 안된다. 둘 모두 추상에 의존적이여야 된다.

- 2. 추상은 구현에 의존적이면 안된다. 구현이 추상을 의존해야 한다.

- 간단하게 말하면 주 클래스가 부 클래스에 직접 의존하면 안되고 인터페이스와 같은 추상을 통해 의존해야 한다는 원칙이다. 멤버변수에 인터페이스를 두거나 인자로 인터페이스를 받는 것이 이 원칙을 따르는 한 예일 것이다.

■ DI (의존성 주입)

- DI는 IoC를 구현하기 위해 사용되는 디자인 패턴으로 클래스 밖에서 의존 객체를 생성하고 여러 방법으로 의존 객체를 연결하는 패턴이다. 이 패턴을 사용하면 의존 객체의 생성과 연결을 클래스 바깥으로 옮길 수 있다.

- DI 패턴에서는 세 종류의 클래스가 정의된다 : Client 클래스, Serice 클래스, Injector 클래스. Client 클래스는 Service 객체를 사용하는 클래스로 Service 클래스에 의존한다. Injector 클래스는 이 Service 객체를 Client 클래스에 주입하는 역할을 한다.

- Injector 클래스가 의존성을 주입하는 방법에는 크게 세가지가 있다. 생성자 주입, 속성 주입, 메소드 주입. 모두 Client의 무언가를 통해 Service 객체를 주입하는데 생성자 주입은 생성자를 통해, 속성 주입은 속성을 통해, 메소드 주입은 메소드를 통해 주입한다.

- 의존성 주입의 예를 들자면 JAVA나 C#의 Stream 클래스와 Reader 클래스의 관계를 예로 들 수 있다. 보통 Reader 클래스를 만들 때 var Reader = new TextReader(fileStream)과 같이 하는데 이는 생성자 주입에 해당하는 예로 Stream은 데이터를 전달하는 것에만 제어를 갖고 Reader는 이를 통해 전달된 데이터를 읽는 것에만 제어를 가짐으로써 제어 역전 원칙을 지키고 5대 원칙 중 단일 책임 원칙도 지킬 수가 있게 된다.

■ IoC Container

- IoC 컨테이너는 의존성 주입을 자동으로 하기 위한 프레임워크로 객체 생성과 수명, 의존성 주입을 관리한다. 여기서 IoC 컨테이너는 객체를 생성하고 모든 의존 객체를 생성자나 프로퍼티, 또는 메소드를 통해 런타임에 넘겨주고 떄가 되면 해제하며 이를 통해 우리가 직접 객체를 만들고 관리하지 않을 수가 있다.

- 모든 IoC 컨테이너는 다음과 같은 동작을 제공한다.

- 1. Register : 컨테이너는 반드시 지정된 타입의 객체를 생성할려고 한다면 어떤 의존성이 있는지 통보받아야 한다.이 과정을 등록(Registration)이라 부르며, 기본적으로 타입과 의존 타입을 연결하는 방법을 컨테이너는 제공해야 한다.

- 2. Resolve : IoC 컨테이너를 사용할 때 객체를 직접 생성하진 않아도 된다. 컨테이너가 이 과정을 전담하며 이를 결합(?)(Resolution)이라고 한다. 컨테이너는 반드시 지정된 타입과 의존 타입을 결합해 생성하는 방법을 제공하며, 이는 정확히는 지정된 타입을 생성하고 필요한 의존성을 주입하고 객체를 반환하는 방법이다.

- 3. Dispose : 컨테이너는 반드시 의존 객체의 수명을 관리한다. 대부분의 IoC 컨테이너는 여러 수명 관리 객체를 통해 의존 객체의 수명을 관리하고 해제한다.

- 아래의 리스트는 이런 IoC 컨테이너를 제공하는 .NET 패키지이다.

- Unity

- StructureMap

- Castle Windsor

- Ninject

- Autofac

- DryIoc

- Simple Injector

- Light Inject


■ 참조

- 위 내용은 아래의 링크에 있는 영문 블로그의 글을 참조해 만들어졌습니다.

- https://www.tutorialsteacher.com/ioc/ioc-container