인프런 김영한 강사님의 <스프링 핵심 원리-기본편> 강의를 정리한 글입니다.
[스프링 프레임워크]
[스프링 부트]
: 객체 지향 프로그래밍은 프로그램을 유연하고 변경이 용이하게 만들기 때문에 대규모 소프 트웨어 개발에 많이 사용된다.
네 가지 객체 지향 프로그램의 특징 중 다형성에 대해서 알아보자.
자바 언어는 다형성을 활용하고 있다.
그 예로는 오버라이드가 있다.

정리를 하자면, 다형성을 활용한다면 유연하고 변경이 용이하며 프로그램을 무한히 확장해 나갈 수 있다. 클라이언트에 영향을 주지 않는 변경이 가능하다. 인터페이스를 안정적으로 설계하는 것이 매우 중요하다.
[SRP]
하나의 클래스는 하나의 책임만 가져야 한다.
변경이 있을 때 파급 효과가 적어야 한다는 의미이다.
[OCP] ⭐️
소프트웨어 요소에는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
인터페이스를 구현한 새로운 클래스를 하나 만드는 것은 기존 코드를 변경하는 것이 아니라 확장하는 개념이다. 그렇지만 다음 예를 살펴보면 OCP 원칙을 지키는 것이 쉽지 않다.

인터페이스를 확장하여 새로운 클래스를 생성하였으나, 실제로 적용하기 위해서는 코드를 수정해야만 한다. 어쩔 수 없는 변경이 필요하다... 이를 해결하기 위해서 연관 관계를 맺어주는 별도의 조립, 설정자가 필요하다. 스프링에서는 스프링 DI 컨테이너가 그 역할을 한다.
[LSP]
프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
예를 들면, 자동차 인터페이스가 있다고 생각보자. 만일 자동차 인터페이스를 확장하서 새롭게 만든 자동차의 엑셀이 뒤로 간다면 어떨까? 기본적으로 엑셀을 밟으면 앞으로 간다는 약속을 깨버린 것이다. 이는 리스코프 치환 원칙이 깨진 것으로 볼 수 있다.
[ISP]
특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다. 인터페이스를 분리하여 설계하면 인터페이스 자체가 변해도 관련 없는 다른 클라이언트에게 영향을 주지 않는다.
[DIP] ⭐️
프로그래머는 추상화에 의존해야지, 구체화에 의존해서는 안된다. 의존성 주입은 이 원칙을 따르는 방법 중 하나이다. 쉽게 이야기해서 구현 클래스에 의존하지 말고, 인터페이스에 의존하라는 의미이다.
그런데 OCP에서 설명한 MemberService는 인터페이스에 의존하지만, 구현 클래스도 동시에 의존한다. 구현 클래스에 의존하지 않는다는 DIP를 위배할 수 밖에 없다. 이를 해결하기 위해서도 마찬가지도 연관 관계를 맺어주는 별도의 조립, 설정자가 필요하다.
다형성만으로는 OCP, DIP를 지킬 수 없다.
이를 해결하기 위해서는 '무엇'이 더 필요한가?
다음은 OCP, DIP를 가능하게 지원해주는 스프링 기술이다.
객체 지향 설계는 유연하게 변경할 수 있도록한다.
이상적으로는 모든 설계에 인터페이스를 구현해야 한다.
그러나, 인터페이스를 구현하기 위해서는 추상화를 하기 위한 비용이 든다.
기능 확장 가능성이 없다면, 구현 클래스를 직접 사용하고 추후에 리팩토링하여 인터페이스를 도입하는 것도 하나의 방법이다.