- 해당 게시물은 인프런 "스프링 핵심 원리 - 기본편" 강의를 참고하여 작성한 글입니다.
- 자세한 코드 및 내용은 강의를 참고해 주시길 바랍니다.
강의링크 -> 스프링 핵심 원리 - 기본편 (김영한)
스프링 이라는 단어는 문맥에 따라 다르게 사용된다.
스프링 부트 는 스프링 프레임워크와 별도로 사용하는 것이 아니다.
=> 여러 스프링 프레임워크를 편리하게 사용할 수 있도록 기능을 제공하는 것
그러면 근본적으로 스프링을 왜 만들었을까?
=> 스프링은 좋은 객체 지향 애플리케이션을 개발할 수 있도록 도와주기 위해 만든 프레임워크
추상화, 캡슐화, 상속, 다형성 등 다양한 객체 지향의 특징이 있지만 프로그램을 유연하고 변경이 용이하게 만들기 위해서는 다형성(Polymorphism) 을 지키는 것이 중요하다.
인터페이스와 구현 객체를 분리한다면 클라이언트는 구현 대상의 내부 구조를 몰라도 되고 구현 대상의 내부 구조가 변경되어도 영향을 받지 않는다.
public class MemberService{
// private MemberRepository memberRepository = new MemoryMemberRepository();
private MemberRepository memberRepository = new JdbcMemberRepository();
}
MemberRepository 인터페이스를 상속받아 오버라이딩한 MemoryMemberRepository와 JdbcMemberRepository 객체를 MemberService 실행 시점에 유연하게 변경할 수 있다.
즉, 클라이언트에 영향을 주지 않으면서 변경 가능하도록 인터페이스를 잘 설계하는 것이 좋은 객체 지향 프로그래밍이다.
- SRP: 단일 책임 원칙(single responsibility principle)
- OCP: 개방-폐쇄 원칙 (Open/closed principle)
- LSP: 리스코프 치환 원칙 (Liskov substitution principle)
- ISP: 인터페이스 분리 원칙 (Interface segregation principle)
- DIP: 의존관계 역전 원칙 (Dependency inversion principle)
OCP는 '소프트웨어 개체는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다' 프로그래밍 원칙인데 위에서 언급된 다형성과 연관 지어 생각해 볼 수 있다. 얼핏 보면 거의 동일한 의미를 가진 것 같지만
public class MemberService{
// private MemberRepository memberRepository = new MemoryMemberRepository();
private MemberRepository memberRepository = new JdbcMemberRepository();
}
구현 객체를 변경하려면 MemberService의 코드를 변경해야 함을 알 수 있다. 분명 다형성을 사용했지만, OCP원칙에는 어긋남을 알 수 있다.
DIP는 '프로그래머는 추상화에 의존해야지, 구체화에 의존하면 안된다'는 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 원칙이다. 위의 코드에서 MemberService는 MemberRepository라는 인터페이스에 의존하지만 동시에 MemoryMemberRepository와 JdbcMemberRepository 구현 클래스에도 동시에 의존한다. 또다시 다형성을 사용했지만 DIP원칙에 어긋났다.
우리는 코드를 통해 다형성만으로는 OCP와 DIP 원칙을 지킬 수 없다는 사실을 확인했다.
맨 처음에 스프링은 좋은 객체 지향 애플리케이션을 개발할 수 있도록 도와주는 프레임워크라고 언급했었다.
스프링은 다형성만으로 지킬 수 없던 OCP와 DIP 원칙을 지킬 수 있도록 DI, DI 컨테이너를 제공한다.
또, DI, DI 컨테이너뿐만이 아니라 객체 지향의 장점을 극대화할 수 있도록 수많은 기능을 제공하고 있다.