- 스프링?
- 스프링은 자바 언어 기반의 프레임워크이다.
- 자바의 가장 큰 특징이 뭘까? - 객체 지향성이다.
- 결국 스프링은 객체 지향 언어가 가진 강력한 특징들을 살려낼 수 있는 프레임워크이다.
- 그럼 살려내야 할 객체 지향 특징이 뭘까?
- 객체 지향의 특징
- 객체 지향의 특징으로는 추상화, 캡슐화, 상속, 다형성 등이 있다. 각각의 특징들을 본 포스팅에서 서술하진 않겠다.
- 그래서 객체 지향적으로 프로그래밍을 하면 좋은 점이 뭘까? 추상화니, 다형성이니 어려운 말 쓰지말고 생각해보자.
- 결론부터 이야기 하자면, 객체 지향 언어의 가장 큰 장점은 "유연성" 이라고 생각한다.
- 객체 지향 프로그래밍은 코드 자체를 명령어들의 집합으로 보는 시선을 벗어나, 독립적인 단위로 구성할 수 있고 상호간의 교류가 가능한 "객체"들의 모임으로 생각한다.
- 이러한 객체의 모임 방식으로 코드를 구성한다면 무언가 수정이 필요한 경우, 해당 클래스만 수정함으로써 원하는 결과를 만들어낼 수 있다.
- 마치 각종 필요한 부품을 조립해서 컴퓨터가 완성되듯이, 필요한 레고 조각을 모아서 작품을 완성하듯이 객체들의 모임으로 원하는 프로그램을 만들 수 있다는 것이 객체 지향 언어의 가장 큰 장점이다.
- 이러한 레고 조립과 같은 특성을 더욱 잘 살려낼 수 있는 "다형성"에 대해서 자세히 알아보자.
- 다형성, 역할과 구현의 분리
- 다형성은 코드를 역할과 구현으로 나눠주는 특징이다.
- 무슨 말일까? 다음 예시를 보자.
- 위 상황은 로미오와 줄리엣을 각각 연기할 수 있는 배우들을 나열해놨다.
- 만약, 로미오라는 "역할"에 대한 "구현체"로 장동건 배우가 발탁되었다면, 줄리엣이라는"역할"에 대한 "구현체"로 어떤 배우가 오던 상관없이 대본에 충실한 채로 연기해야만 할 것이다. 상대가 누구던 상관없이 역할에 충실하는게 훌륭한 배우가 아니겠는가?
- 이와 같이 역할과 구현을 구분해, 역할에 충실하도록 하는게 바로 "다형성"이다. 이번에는 실제 자바 코드를 예시로 보자.
- MemberRepository를 호출하는 MemberService(클라이언트) 입장에서는 저장소라는 "역할"에만 관심이 있을 뿐이지 실제로 로컬 메모리를 사용하는 저장소인지, 상용 데이터베이스를 사용하는 저장소인지는 궁금하지가 않다. 뭐가 됐든 저장소라는 "역할"을 원해서 호출했을 뿐이다.
- 다른 관점으로 이야기 해보자. 실제 개발 환경에서, 어떤 데이터베이스를 사용해 프로덕션 환경을 구성할지 결정이 안됐다면, 개발자들은 결정이 될 때까지 마냥 기다려야 하는가? 절대 아니다.
- 위 사진에서 보듯이, 저장소의 "역할"을 맡고있는 인터페이스를 만들고 실제 해당 역할의 구현체를 만들어서 사용하면 어떤 저장소를 필요로 하던지 갈아 끼우기만 하면 된다! --> 오버라이딩을 통해 가능
- 이것이 다형성의 강력함이다.
public class MemberService {
// private MemberRepository memberRepository = new MemoryMemberRepository();
private MemberRepository memberRepository = new DBMemberRepository();
/* 역할(인터페이스) = new 구현체(상속받은 클래스) 형식 */
/* 구현체만 갈아끼우면 조립 완성 */
}
- 이처럼 역할과 구현의 분리를 통해 클라이언트에 영향을 주지 않는 변경이 가능해졌다.
- 스프링은 이러한 다형성을 극대화해서 이용할 수 있도록 도와준다.
- 제어의 역전(IoC), 의존관계 주입(DI)은 다형성을 활용해서 역할과 구현을 편리하게 다룰 수 있도록 지원한다.
- 좋은 객체 지향 설계의 5가지 원칙 (SOLID)
- SRP : 단일 책임 원칙(Single Responsibility Priciple)
- 한 클래스는 하나의 책임만 가져야 한다.
- 하나의 책임이라는 것은 문맥과 상황에 따라 다르다.
- 코드의 변경이 있을 때, 변경에 따른 파급효과가 적으면 단일 책임 원칙을 잘 따른 것이다. - OCP : 개방 - 폐쇄 원칙 (Open/Closed Principle)
- 소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀 있어야 한다.
- 다형성을 생각해보자. 레고의 조립처럼 확장에는 열려있었고 최소한의 변경을 요구하도록 코드를 구성했다.
- 사실 아직 다형성 만으로 OCP를 완벽하게 지킬 순 없다. 위 예제도 클라이언트 코드를 어찌됐건 변경을 했다.
- 뒤로 나아갈수록 OCP를 지키기 위한 방식이 나온다. - LSP : 리스코프 치환 원칙 (Liskov Substitution Principle)
- 다형성에서, 하위 클래스는 인터페이스의 규약을 다 지켜야한다.
- 예를 들어, 전진 기능의 인터페이스를 만들었다. 이를 상속받은 하위 클래스가 물론 코드상으로 엑셀을 밟을 때 -30의 속도를 내도록 코드를 작성할 수 있겠지만, 이는 인터페이스의 규약을 따르지 않은 것이다. - ISP : 인터페이스 분리 원칙 (Interface Segregation Principle)
- 특정 클라이언트를 위한 인터페이스는 하나보다 여러 개가 낫다
- 자동차 인터페이스 -> 운전 인터페이스, 정비 인터페이스로 분리
- 분리하면 각각의 목적이 분명해진다. - DIP : 의존관계 역전 원칙 (Dependency Inversion Principle)
- 추상화(인터페이스)에 의존해야지, 구체화(상속받은 클래스)에 의존하면 안된다.
- 계속 이야기한 역할 자체에 초점을 둬야한다는 원칙이다.
- 위 예제 코드를 보면, 클라이언트인 MemberService는 역할(MemberRepository)에도 의존하고
구현체(Memory & DB Repository)에도 의존한다. --> DIP 위반
- 이를 해결하기 위한 방법은 OCP와 마찬가지로 뒤로 갈수록 나온다.
- 정리
- 객체 지향의 핵심은 다형성이다.
- 오직 다형성 만으로는 쉽게 부품을 갈아 끼우듯이 개발할 수는 없다.
- 다형성 만으로는 OCP, DIP를 지킬 수 없다.
- 뭔가 더 필요하다.
- 스포하자면, 스프링은 DI(Dependency Injection), DI 컨테이너를 통해 OCP, DIP를 가능하게 지원한다.
출처 : 인프런, 김영한의 스프링 핵심 원리 - 기본편
'Spring' 카테고리의 다른 글
[Spring] 의존관계 자동주입, @Autowired (1) | 2023.07.02 |
---|---|
[Spring] 컴포넌트 스캔, @ComponentScan (0) | 2023.06.26 |
[Spring] 싱글톤 패턴, 싱글톤 컨테이너 (0) | 2023.06.26 |
[Spring] 순수 자바 DI컨테이너에서 스프링 컨테이너로 전환하기 (0) | 2023.06.26 |
[Spring] 순수 자바코드를 통해 회원관리, 주문서비스를 만들고 객체지향원리 적용하기 (0) | 2023.06.23 |