Posts Spring IoC, DI란?
Post
Cancel

Spring IoC, DI란?

IoC(Inversion of Control)


번역하면 제어의 역전이다.
이게 무슨말일까 설명을 들으면 이해가 된다.
기존 프로그램은 클라이언트 구현 객체가 스스로 필요한
서버 구현 객체들을 생성하고, 연결하고 실행했다.

예를들면 운전자가 차를 고를 수 있는 상황을 생각해보자
Interface Car

1
2
3
public interface Car {
    String Go();
}

SuperCar.java

1
2
3
4
5
6
public class SuperCar implements Car {
    @Override
    public String Go() {
        return "부아앙";
    }
}

OldCar.java

1
2
3
4
5
6
public class OldCar implements Car {
    @Override
    public String Go() {
        return "털털털";
    }
}

Driver.java

1
2
3
4
5
6
7
8
9
10
11
import hello.core.car.Car;
import hello.core.car.SuperCar;

public class Driver {
    public static void main(String[] args) {
        Car car = new SuperCar();
        System.out.println(car.Go());
    }
}

// 실행결과 : 부아앙

위의 코드처럼 Driver에서 new를 이용해 직접 자동차를 선택한다.
구현객체가 스스로 제어 흐름을 조종하는 것이다.

하지만 위의 코드는 DIP, OCP를 지키지 않은 코드이다.

AppConfig를 이용해 DIP, OCP를 만족하는 코드로 바꿔보면

AppConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
import hello.core.car.Car;
import hello.core.car.SuperCar;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {
    @Bean
    public Car car() {
        return new SuperCar();
    }
}

그리고 Driver.java를 바꿔준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
import hello.core.car.Car;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Driver {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
        Car car = applicationContext.getBean("car", Car.class);
        System.out.println(car.Go());
    }
}

// 실행결과 : 부아앙

이제 다시 코드를 보자
구현 객체가 더 이상 스스로 제어 흐름을 조절할 수 없게 되었다.
SuperCarOldCar를 선택하는 것은 AppConfig가 하게된다.
AppConfig가 생기고 난 후에 구현 객체는 자신의 로직을 실행하는 역할만 담당한다.
프로그램의 제어 흐름은 이제 AppConfig가 가지고 있다.

이렇게 프로그램의 제어 흐름을 직접 제어하는 것이 아니라
외부에서 관리하는 것을 제어의 역전(IoC)라고 한다.



DI(Dependency Injection)


의존관계는 정적인 클래스 의존 관계와 실행 시점에 결정되는 동적인 객체(인스턴스) 의존 관계
이 둘을 분리해서 생각해야 한다.

정적인 클래스 의존관계

정적인 의존관계는 어플리케이션을 실행하지 않고서도 분석할 수 있다.
클래스가 사용하는 import 코드를 보고 의존관계를 쉽게 판단 가능하다.

아래 예시 클래스다이어그램을 보면

SuperCarOldCarCar를 상속받아 의존한다.
또한 DriverCar에 의존하는 것을 알 수 있다.
그런데 이러한 의존관계 만으로는 실제로 어떤 객체가 Driver에 주입되는지 알 수 없다.

동적인 클래스 의존관계

어플리케이션 실행 시점에 실제 생성된 객체 인스턴스의 참조가 연결된 의존 관계이다.

애플리케이션 실행 시점에 외부에서 실제 구현 객체를 생성하고
클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결 되는 것을
의존관계 주입이라 한다.

객체 인스턴스를 생성하고 그 참조값을 전달해서 연결된다.

의존관계 주입을 사용하면 클라이언트 코드를 변경하지 않고
클라이언트가 호출하는 대상의 타입 인스턴스를 변경할 수 있다.

-> SuperCar를 선택할지 OldCar를 선택할지 변경할 수 있다는 것이다.

의존관계 주입을 사용하면 정적인 클래스 의존관계를 변경하지 않고
동적인 객체 인스턴스 의존관계를 쉽게 변경할 수 있다.

-> 위의 정적인 클래스다이어그램의 수정없이
즉, 클라이언트 코드의 수정없이 자동차의 종류 변경이 가능하다.

위에서 쓴 AppConfig 처럼 객체를 생성하고 관리하면서
의존관계를 연결해 주는 것을 IoC 컨테이너 혹은 DI 컨테이너라고 한다.

백준 11070 피타고라스 기댓값 c++

백준 2270 하노이 탑 c++

Comments powered by Disqus.