열심히 쓰던 와중 글이 날아가버리는 참사가 일어났다... 인생..
어찌저찌 스프링에 대해 자세히 알고 싶어서 토비의 스프링을 읽었다. 이러쿵 저러쿵해서 책이 참 마음에 들었다.
앞선 내용으로 상속과 인터페이스의 사용에 대해 2시간넘게 서술했는데..
가슴은 아프지만 누구 보여주려고 쓰는 것도 아니니.. 그냥 날아간 부분은 버리고 작성해보겠다..ㅜ
상속 - 템플릿/팩토리 메서드 패턴과 인터페이스를 이용해 중복 코드를 제거하고 코드간의 관심사를 분리해보자.
SOLID
단일 책임 원칙
: 한 클래스에는 하나의 책임만이 있어야 한다.
개방 폐쇠 원칙
: 확장에는 열려있고 변화에는 닫혀있어야 한다.
리스코프 치환 원칙
: 상위 개념은 깨뜨리지 않으면서 하위 타입의 인스턴스와 호환되어야 한다.
인터페이스 분리 원칙
: 하나의 범용 인터페이스보다 특정 개체의 인터페이스 여러 개가 낫다.
의존관계 역전 원칙
: 구체화보다 추상화에 의존해라
이에 관해 자동으로 나오는 것이 응집도와 결합도.
코드의 응집도가 높을 수록 하나의 모듈, 클래스가 하나의 책임에만 집중되어 있다는 뜻이다.
결합도가 낮을 수록 책임과 관심사가 다른 오브젝트 또는 모듈과는 느슨하게 연결된 형태를 유지하는 것이 바람직하다.
그럼 이제 IoC에 대해 알아보자.
Ioc는 Inversion of Control 의 약자로 제어의 역전이라는 뜻이다.
일반적인 프로그램 흐름에서 사용자가 제어를 하는 것이 아닌 외부로 제어를 넘기는 것이다.
- 클라이언트는 구체적인 팩토리 클래스를 알 필요가 없다.
애플리케이션이 발전하면 IoC를 적용한 오브젝트도 계속 추가될 것이다.
그럴 때 마다 팩토리 오브젝트를 생성하기에는 번거롭다. 스프링 애플리케이션 컨텍스트를 사용하면 오브젝트 팩토리가 아무리 많아져도 이를 알아야하거나 직접 사용할 필요가 없다.
- 애플리케이션 컨텍스트는 종합 IoC 서비스를 제공해준다.
애플리케이션 컨텍스트의 역할은 단지 오브젝트 생성과 다른 오브젝트와의 관계설정만이 전부가 아니다.
오브젝트가 만들어지는 방식, 시점과 전략, 자동생성, 후처리, 정보의 조합, 설정방식의 변화, 인터셉트 등 여러 기능들을 제공한다.
스프링에게 IoC, 객체에 대한 제어를 넘기면서 우리는 그에 대한 책임과 관리에서 자유로워지는 것이다.
필요할 때는 스프링이 빈을 제공하는 다양한 검색 방법을 사용해서 사용하면 된다.
이는 객체 간의 결합도를 낮추고 응집도를 높여준다.
클래스나 객체 간의 엮임 없이, 필요할 때는 언제든 주입해서 사용할 수 있다.
! 반대로 생각해서 IoC가 없는 경우를 생각해보자.
- 낮은 결합도를 유지하기 힘들다
- 객체의 스코프 관리를 직접 해줘야 하기 때문에 복잡해져, 코드의 유지보수성이 낮아진다
- 비슷한 코드에서 코드 중복이 발생할 수 있다, 코드의 재사용성이 낮아진다.
- 객체의 생성과 사용이 밀접하게 연결되어 있어서 테스트가 어렵다.
- 객체 생성 방식이나 종속성이 변경될 경우 관련된 모든 코드를 수정해야 하기 때문에 변경에 대한 대응이 낮아진다.
- DI : 의존 관계 주입
Ioc와 DI는 스프링 개발자라면 지겹도록 봤을 것이다.
하지만 누가 툭 물어봤을 때 깔쌈하게 대답할 수 있을까?
어느정도 대답은 할 수 있는데 자신은 없다면 무한 반복을 하도록 하자.. ( 블로그에 3번째 적는듯 )
객체를 생성하고 관계를 맺어주거나 관리하는 작업을 담당하는 기능을 일반화 한 것이 스프링 IoC 컨테이너 이다.
DI는 오브젝트 레퍼런스를 외부로 부터 제공받고 이를 통해 오브젝트 간의 관계가 다이내믹 하게 만들어 지는 것이 핵심이다.
그렇다. 깔쌈하게 말하기 위해선 특정 단어를 외우는게 가장 좋다. 오브젝트 레퍼런스, 다이내믹 관계를 기억하자.
인터페이스를 이용하여 A가 B를 사용하는 의존 관계를 만들면 A는 B가 변경되면 영향을 직접적으로 받게 된다.
하지만 B는 A가 변경되어도 전혀 영향을 받지 않는다. 이것이 의존관계를 사용하여 결합도를 낮춘 것이다.
인터페이스를 통해 의존관계를 제한해주면 그만큼 변경에서 자유로워 진다. 결합도가 낮아진 만큼 응집도 또한 높일 수 있을 것이다.
DI 컨테이너는 자신이 결정한 의존관계를 맺어줄 클래스의 오브젝트를 만들고 생성자의 파라미터로 오브젝트의 레퍼런스를 전달해준다.
우리가 흔히 @Autowired 해서 사용하는 그것이다.
A가 B를 사용할 때, 직접 new 를 사용해서 객체를 생성하는 것이 아닌 A에 B를 컨테이너가 미리 생성하여 주입 해준다.
이것이 의존 관계 주입이다.
A는 B를 new로 직접 생성하지 않기 떄문에 B의 생성방식이 변경되어도 A의 구현을 수정할 일이 없다.
B또한 생성방식을 변경해도 A의 구현을 수정할 일이 없다. 하지만 A는 B를 의존하고, 사용하고 있다.
자신이 사용할 오브젝테 대한 선택과 생성 제어권을 외부로 넘기고 자신은 수동적으로 주입받은 오브젝트를 사용하는 것이 IoC의 개념과 잘 들어맞는다.
그래서 스프링하면 Ioc 컨테이너, DI 컨테이너 등과 같이 지칭하기도 하는 것이다.
! DI가 없다면?
- 객체가 다른 객체를 직접 참조하거나 생성하면 강한 결합도가 발생하기 때문에 유연성에 문제가 생긴다.
- 객체가 직접 의존 객체를 생성하면 의존성이 변경될 때 해당 객체의 코드를 변경해야 한다.
- 결합도가 증가하여 재사용성이 저하된다.
- 각 객체간 의존성 관리에 어려움을 겪게 된다.
또한 외부에서의 주입만이 아니라 의존관계 검색을 통해 객체를 가져올 수 있다.
책의 뒤의 내용은 방금 설명한 내용을 아주 간단한 코드부터 시작하여 어떻게 의존관계 주입을 응용하는지에 대해 나와있지만
내가 알고 싶은건 의존관계 주입 사용법이 아닌 원리였으므로 여기까지 서술하겠다..
앞에 나름 열심히 썻는데 날아가버려 가슴이 아파 대충 썻다... ㅠㅠ