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

• 프로그램의 제어 흐름을 직접 제어하는 것이 아니라, 외부에서 관리하는 것

 객체의 생성과 소멸, 그리고 객체간의 의존관계를 설정하는 행위

    -  모두 프레임워크가 대신 해준다 : 주도권이 역전됨 → 제어의 역전

    -  프레임워크가 흐름을 주도하면서 개발자가 만든 어플리케이션 코드를 사용한다.

 이렇게 IoC가 일어나는 공간을 IoC 컨테이너라고 부른다.

 

도대체 무슨 말이야

 분명 코드를 작성한건 나인데, 왜 자꾸 주도권이 프레임워크에 있다는 거지? 🤔

 → 이를 이해하기 위해, 프레임워크를 사용할때와 사용하지 않을 때를 비교해보자

 

1 )  직접 객체를 생성하고 의존관계를 설정해주는 경우

public class BeanKor {
    public void sayBean(String name){ System.out.println("한국 콩!"); }
}

public class BeanEng {
    public void sayBean(String name){ System.out.println("English Bean!"); }
}
public class YummyBean {
    public static void main(String[] ars){
        BeanKor bean = new BeanKor(); // 한국 콩!
        // BeanEng bean = new BeanEng(); // English Bean!
        bean.sayBean();
    }
}

• main에서 BeanEng를 BeanKor로 바꿔줘야 함 : YummyBean은 BeanEng/Kor에 의존성을 가지고 있다

    -  YummyBean의 기능을 바꾸고자 할 때, BeanEng/Kor도 함께 바꿔줘야 하기 때문이다.

    -  이러한 번거로움을 해결해주기 위해서는 객체의 인스턴스를 외부에서 생성받을 필요가 있다. (의존성 주입)

2 )  의존관계를 외부로부터 받아오는 경우 (의존성 주입)

public interface Bean { public void sayBean(); }

public class BeanKor implements Bean{
    public void sayBean(){ System.out.println("한국 콩!"); }
}

public class BeanEng implements Bean{
    public void sayBean(){System.out.println("English Bean!");}
}
public class YummyBean {
    public static void main(String[] ars){
        Bean bean = new BeanKor(); // 한국 콩!
        // Bean bean = new BeanEng(); // English Bean!
        bean.sayBean();
    }
}

• 하지만 여전히 출력되는 값을 바꾸기 위해선 소스코드의 수정이 필요하다.

 더 개선시킬 수 있을까?

3 )  프레임워크가 대신 객체를 생성하고 의존관계를 설정해주는 경우 (IoC)

public interface Bean { public void sayBean(); }

public class BeanKor implements Bean{
    public void sayBean(){ System.out.println("한국 콩!"); }
}

public class BeanEng implements Bean{
    public void sayBean(){ System.out.println("English Bean!"); }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:schemaLocation=".../beans/spring-beans.xsd">

		<bean id="Bean" class="BeanKor"/>
		<!--<bean id="Bean" class="BeanEng"/>-->
</beans>
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.FileSystemResource;

public class YummyBean {
    public static void main(String[] ars){
        BeanFactory factory = new XmlBeanFactory
                             (new FileSystemResource("resources/beans.xml"));

        Bean bean = factory.getBean("bean", Bean.class);
        bean.sayBean(); // 한국 콩!
    }
}

• 소스 코드의 변경 없이 환경설정만으로도 프로그램을 제어할 수 있다

• 이것이 가능한 이유는, 객체의 생성과 주입을 모두 스프링 프레임워크가 주도하고 있기 때문 (IoC)

    -  프로그래머는 BeanKor 클래스와 BeanEng클래스를 정의하기만 했다.

    -  기존 코드에서처럼 bean에 BeanKor를 넣어줄지, BeanEng를 넣어줄지 결정하지도 않았고,
        new BeanKor( ) 따위의 생성자로 객체를 생성하지도 않았다.

    -  스프링이 스스로 설정 파일을 읽고, 거기 써져 있는대로 객체를 생성한 다음 반환해줬다 : '주도권' 을 가짐

프레임워크가 생산성을 높여주는 이유

• 프레임워크는 뼈대를 제공하고, 그 위에 개발자가 코드를 올려 동작하게끔 한다.

• 개발자 입장에선 로직에 더 집중할 수 있고, 객체지향 개발에 있어서 시스템을 일관성있게 관리할 수 있다.

• 여러 개발자들이 각자의 취향에 따라 설계하고 코딩한다면 관리가 어렵지만, 프레임워크가 제공하는 뼈대와 가이드에 따라 개발하면
    시스템의 유지/보수가 용이하다.

• 예) 기존에 쓰던 객체를 버리고, 새로운 객체를 사용해야 하는 경우

    -  [상황] 5000원 할인권만 뿌리고 있었는데, 50% 할인권을 뿌려야 한다고요?

        ◦ (1)의 방법 : 새 클래스 정의하고, 코드 일일이 돌면서, ctrl+f 해가면서, 일일이 수정 작업 ㅠ

        ◦ (3)의 방법 : 새 클래스를 정의한 다음, 설정 파일만 수정해주면 끝!

 

참고자료

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...

www.inflearn.com

 

IOC와 DI 에 대하여 (스프링 개념 이해하기 쉽게 설명)

Inversion of Control (제어의 역전) DI(의존성 주입)을 이해하기 위해서는 IoC(제어의 역전) 의 개념을 알고 넘어가야 할 필요가 있다. 스프링을 쓰기 전에는 개발자가 프로그램의 흐름(애플리케이션

mo-world.tistory.com