스프링은 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크입니다. 오늘은 스프링의 진짜 핵심인 좋은 객체 지향 설계에 대해 알아보고자 합니다.
소프트웨어 설계를 이해하기 쉽고 유연하고 유지보수가 쉽게 만들기 위해 나온 원칙
한 클래스는 하나의 책임만 가져야한다.
하지만 하나의 책임이라는 것은 모호하다. 클 수 있고, 작을 수 있기 때문이다. 그래서 중요한 판단 기준은 변경에 있다. 변경이 있을 때 파급 효과가 적으면 단일 책임 원칙을 잘 따른 것이라고 할 수 있다.
확장에는 열려 있고 변경에는 닫혀 있어야 한다.
클래스 내부 수정없이 동작을 확장할 수 있어야한다 라는 의미이다.
그런데 뭔가 좀 이상하다. 확장을 하려면 당연히 기존 코드를 변경해야할 것 같다. 다형성을 활용해보자!
public class MemberService {
private MemberRepository memberRepository = new MemoryMemberRepository();
}
public class MemberService {
// private MemberRepository memberRepository = new MemoryMemberRepository();
private MemberRepository memberRepository = new JdbcMemberRepository();
}
MemberService 클라이언트가 구현 클래스를 직접 선택하고 있다.
확장은 열려 있지만 구현 객체를 변경하려고 클라이언트 코드를 변경하는 것이다. 분명 다형성을 사용했지만 OCP 원칙을 지킬 수 없다.
이러한 문제점은 스프링의 DI, IOC 컨테이너가 해결해준다.
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다
그러기 위해서
특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
추상화에 의존하고, 구체화에 의존하면 안된다.
쉽게 이야기해서 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 뜻이다.
그런데 OCP에서 설명한 MemberService는 인터페이스에 의존하지만, 구현 클래스도 동시에 의존한다. 이는 DIP를 위반한 것이다.