그동안 '제어의 역행'에 대해 명확히 정리되지 않았었다.
하여 이번에 '제어의 역행'을 명료하게 정리하고자 포스팅을 작성하였다.
제어의 역행 이란
제어의 역행(Inversion of Control)은 결국 ‘객체’에 대한 것이다.
한 클래스에서 객체 A가 필요하다고 하자.
이 클래스에서 객체 A를 사용하려면 일반적으로는 객체 A를 생성하는 객체 생성문이 있어야 한다.
즉
객체A objA = new 객체A();
위 생성문이 있어야 객체를 생성해내고 그걸 이용할 수가 있을 것이다.
위와 같은 ‘직접 객체 생성문을 작성하는 방식’이 엔터프라이즈 애플리케이션 개발에서 좋지 않은 이유 및 한계
단도직입적으로 말하면 객체지향적이지 않고, 유지보수성이 나쁘다.
- 유지보수성이 나쁘다
엔터프라이즈 애플리케이션은 클래스가 매우 많다. 수백수천수만 개가 될 수 있다.
근데 해당 서비스의 요구사항이 변경돼서 어떤 객체를 변경해야 되는데
그 객체를 사용하고 있던 클래스가 수천 개이며 거기에 전부 직접 객체 생성문으로 작성되어 있다면,
이를 전부 찾아내고 전부 수정하는데 엄청난 공수가 들 것이다.
- 객체지향 원칙 중 ‘개방 폐쇄 원칙(OCP)’에 어긋난다.
객체지향적 애플리케이션 개발을 위해선 “확장에는 열려있고(Open) 기존 코드 수정에는 닫혀(Closed) 있어야 한다”는 OCP원칙이 지켜져야 한다.
근데 만약 직접 객체 생성문으로 작성되어 있다면 해당 객체를 변경해줘야 할 때 객체 생성문 부분을 수정해줄 수밖에 없다.
위의 문제점들을 해결하기 위해 나온 것이 ‘제어의 역전(Inversion of Control: IoC)’이다.
이렇게 객체 관련 코드를 클래스 소스 상에 직접 작성하는 것이
- OCP 위반
- 유지보수성 악화
의 문제를 낳기 때문에, 이를 해결하기 위하여 나온 기술이 제어의 역전(IoC)이다.
※제어의 역전(IoC)은 엄밀히 말해
- DL (Dependency Lookup)
- DI (Dependency Injection)
두 가지가 있다.
근데 현실에서 IoC와 용어를 혼용해서 사용하곤 하는 것은 보통 대부분 DI(의존성 주입) 경우다.
제어의 역전은
- 객체 생성문을 직접 작성해서 해당 객체를 이용할 수 있게 하는 게 아닌
- 객체가 필요한 곳에 (*어딘가로부터 객체를 가져와서) 객체를 주입(Injection)해줌으로써 해당 객체를 이용할 수 있도록 해주는 것이다. (*어딘가: 스프링 컨테이너)
이것의 효과는 다음과 같다
→ “객체의 생성과 객체 간 의존관계에 대한 코드가 클래스 소스 상에서 완전히 사라짐”
객체의 생성 코드와 객체 간의 의존관계를 설정하는 코드가 소스에서 사라지면
— 객체를 변경해줘야 할 때 해당 객체를 사용 중인 모든 클래스에서 소스를 수정해주지 않아도 된다.
— 객체지향의 OCP원칙(개방 폐쇄 원칙)을 위반하지 않는다.
가 된다.
이를 통하여
⇒ 훨씬 더 유연하고(컴포넌트[객체] 간 결합도가 낮고) 유지 보수하기 좋은 애플리케이션을 개발하고 운용할 수가 있게 된다.
객체 생성과 객체 의존관계를 대신 설정하고 관리하는 곳 : 스프링 컨테이너
스프링 애플리케이션 내의 여러 클래스에서 사용할 각각의 객체들을 생성하고 의존관계를 설정하는 작업을 대신 수행하는 곳이 ‘스프링 컨테이너’ 다.
(혼용해서 쓰는 말로 IoC 컨테이너, DI 컨테이너 등도 있다)
이 스프링 컨테이너에서
- 스프링 애플리케이션에서 사용할 모든 객체(컴포넌트)들을 생성하고
- 이 객체들 간의 의존관계를 처리해준다.
애플리케이션이 실행되면
스프링 컨테이너는 구동되면서 한꺼번에 위 2가지 작업들을 수행하여 스프링 Bean들을 등록해두며,
객체가 필요한 곳에 해당 객체(스프링 Bean)를 주입해준다.
→ 이럼으로써 객체가 필요한 클래스에선 객체의 생성 및 의존관계에 대한 코드 없이도 객체를 이용할 수 있다.
정리
제어의 역전(IoC)은 객체가 필요한 클래스에서, 객체의 생성 및 의존관계에 대한 코드 작성 없이도 해당 객체를 이용할 수 있게 해주는 방식이다.
이를 통하여
- 객체[컴포넌트] 간 낮은 결합도
- OCP원칙을 위반하지 않는 객체지향적 코드
를 얻을 수 있으며
이는 결국 유지보수성이 좋은 코드를 낳게 한다.