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)의 방법 : 새 클래스를 정의한 다음, 설정 파일만 수정해주면 끝!
참고자료