![[스프링 핵심 원리 - 기본편] 1. 객체 지향 설계와 스프링](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBebpX%2FbtsAMloeqHH%2Fx11aFnRDyR3ac6Di5eFXjk%2Fimg.png)
[스프링 핵심 원리 - 기본편] 1. 객체 지향 설계와 스프링Backend/Spring2023. 11. 23. 17:36
Table of Contents
인프런 김영한 강사님의 스프링 핵심 원리 - 기본편을 수강하고 정리한 글입니다.
스프링 핵심 원리 - 기본편 - 인프런 | 강의
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보세요! 📢
www.inflearn.com
📌 Spring이란?
✅ Spring Framework
- 핵심 기술 : Spring DI Container, AOP, Event ...
- 웹 기술 : Spring MVC, Spring WebFlux
- 데이터 접근 기술 : Transaction, JDBC, ORM 지원, XML 지원
- 기술 통합 : Cache, 이메일, 원격접근, Scheduling
- 테스트 : Spring 기반 Test 지원
- 언어 : Kotiln, Groovy
이 강의에서는 핵심 기술에 집중한다.
✅ SpringBoot
- 스프링을 편리하게 사용할 수 있도록 지원
- 최근에는 기본적으로 사용
- 없으면 불편해진... 너무 소중해
- 단독으로 실행할 수 있는 스프링 어플리케이션을 쉽게 생성 가능
- Tomcat 같은 웹 서버를 내장하여 별도의 웹 서버 설치 X
- 손쉬운 빌드 구성을 위한 starter 종속성 제공
- 스프링과 3rd parth(외부) 라이브러리 자동 구성
- 메트릭, 상태 확인, 외부 구성 등 프로덕션 준비 기능 제공
- 관례에 의한 간결한 설정
- 기본적으로 SpringBoot 만으로는 돌아가지는 않는다.
- SpringBoot를 쓰면 알아서 Spring Framework를 가져온다.
✅ 스프링의 핵심
- 스프링은 Java 언어 기반 프레임워크
- 자바 언어의 가장 큰 특징 : 객체 지향 언어
- 스프링은 객체 지향 언어가 가진 강력한 특징을 살리는 프레임워크
- 스프링은 좋은 객체 지향 어플리케이션을 개발할 수 있도록 도와주는 프레임워크
📌 좋은 객체 지향 프로그래밍이란?
✅ 객체란?
- 객체 : 모든 실재(實在)하는 대상
- 객체 지향 프로그래밍의 가장 기본적인 단위이자 시작점
- 우리가 보고 느끼고 인지할 수 있는 그 모든 것
✅ 객체 지향 프로그래밍의 특징
- 추상화
- 캡슐화
- 상속
- 다형성
객체 지향 프로그래밍의 4가지 특징ㅣ추상화, 상속, 다형성, 캡슐화 -
객체 지향 프로그래밍은 객체의 유기적인 협력과 결합으로 파악하고자 하는 컴퓨터 프로그래밍의 패러다임을 의미합니다. 객체 지향 프로그래밍의 기본적인 개념과 그 설계를 바르게 하기 위
www.codestates.com
✅ 객체 지향 프로그래밍
- 객체 지향 프로그래밍 : 컴퓨터 프로그램을 명령어의 목록으로 보는 시각에서 벗어나, 여러 독립된 단위, 즉 '객체'들의 모임으로 파악하고자 하는 것이다.
- 유연하고 변경이 용이 = 다형성 (Polymorphism)
- 모든 것을 역할과 구현으로 구성한다.
- 역할과 구현으로 구분하면 단순해지고, 유연해지며, 변경이 편리해진다.
✅ 자바 언어에서의 역할과 구현의 분리
- 자바 언어의 다형성을 활용
- 역할 : 인터페이스
- 구현 : 인터페이스를 구현한 클래스, 구현 객체
- 객체를 설계할 때 역할과 구현을 명확히 분리
- 객체 설계 시, 역할(인터페이스)을 먼저 부여하고, 그 역할을 수행하는 구현 객체를 그 다음으로 만든다.
- 핵심은 구현보다 역할이 먼저다.
- 인터페이스가 더 중요하다!
✅ 자바 언어의 다형성
- 오버라이딩
- 다형성으로 인터페이스를 구현한 객체를 실행 시점에 유연하게 변경할 수 있다.
- 클래스 상속 관계도 다형성과 오버라이딩이 적용 가능하다.
public class MemberService {
private MemberRepository memberRepository = new MemoryMemberRepository();
}
public class MemberService {
private MemberRepository memberRepository = new JdbcMemberRepository();
}
✅ 다형성의 본질
- 인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경할 수 있다.
- 클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경할 수 있다.
✅ 한계
- 역할(인터페이스) 자체가 변경되면 클라이언트, 서버 모두에 큰 변경이 발생
- 하나의 인터페이스가 가지는 구현 클래스는 여러가지 일 수 있고, 그 구현 클래스를 통해 클라이언트는 정보를 주고받고 하기 때문이다!
- 따라서 인터페이스를 안정적으로 잘 설계하는 것이 중요하지만, 어쩔 수 없는 한계이기도 하다.
✅ 스프링과 객체 지향
- 스프링은 다형성을 극대화하여 이용할 수 있도록 도와준다.
- 스프링의 제어의 역전(IoC), 의존관계 주입(DI)은 다형성을 활용해서 역할과 구현을 편리하게 다룰 수 있도록 지원한다.
- 스프링을 사용하면 구현을 즉, 인터페이스를 편리하게 변경할 수 있다.
📌 좋은 객체 지향 설계의 5가지 원칙 (SOLID)
✅ SOLID
- 클린 코드로 유명한 로버트 마틴이 좋은 객체 지향 설계의 5가지 원칙을 정리한 것이다.
- SRP : 단일 책임 원칙 (Single Responsibility Principle)
- OCP : 개방-폐쇄 원칙 (Open/Closed Principle)
- LSP : 리스코프 치환 원칙 (Liskov Substitution Principle)
- ISP : 인터페이스 분리 원칙 (Interface Segregation Principle)
- DIP : 의존관계 역전 원칙 (Dependency Inversion Principle)
✅ SRP (단일 책임 원칙, Single Responsibility Principle)
- 한 클래스는 하나의 책임만 가져야 한다.
- 중요한 기준은 변경
- 변경이 발생했을 때 파급 효과가 적다는 것은 곧, 단일 책임 원칙을 잘 따른 것이라고 볼 수 있다.
✅ OCP (개방-폐쇄 원칙, Open/Closed Principle)
- 소프트웨어 요소는 확장에는 열려있으나 변경에는 닫혀있어야 한다.
- 다형성을 활용해야 하는 원칙이다.
- 인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현하는 것이다. (위에서 계속 얘기했던 내용이다!)
✅ OCP, 개방-폐쇄 원칙의 문제점
- 결국은 클라이언트가 구현 클래스를 직접 선택하는 구조다.
- MemberRepository m = new MemoryMemberRepository(); // 기존 코드
- MemberRepository m = new JdbcMemberRepository(); // 변경 코드
- 구현 객체를 변경하려면 클라이언트 코드를 변경해야 한다.
- 분명 다형성을 사용했지만 OCP 원칙을 지킬 수 없는 것이다.
- 해결법?
- 객체를 생성하고, 연관관계를 맺어주는 별도의 조립, 설정자가 필요하다!!
✅ LSP (리스코프 치환 원칙, Liskov Substitution Principle)
- 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
- 다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야 한다는 것
- 다형성을 지원하기 위한 원칙
ex> 자동차 인터페이스의 엑셀은 앞으로 가라는 기능인데, 뒤로 가게 구현하면 LSP 위반이다.
✅ ISP (인터페이스 분리원칙, Interface Segregation Principle)
- 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
ex> 자동차 인터페이스 -> 운전 인터페이스, 정비 인터페이스를 분리
사용자 클라이언트 -> 운전자 클라이언트, 정비사 클라이언트로 분리
결국 분리하면 정비 인터페이스 자체가 변하더라도 운전자 클라이언트에 영향을 주지 않음!
- 기능 별로 분리하면 인터페이스가 명확해지고, 대체 가능성이 높아진다.
✅ DIP (의존관계 역전 원칙, Dependency Inversion Principle)
추상화에 의존해야지, 구체화에 의존하지 말자!
- 의존성 주입(DI)
- 의존한다? == 내가 저 코드를 알고 있다
- 구현 클래스에 의존하지 말고, 인터페이스에 의존해라.
- 기능이 아니라, 역할에 의존해라.
- 구현체에 의존하게 되면 유연한 구현체 변경이 어려워진다.
- 그런데 MemberService는 인터페이스에 의존하지만, 구현 클래스도 동시에 의존한다. 아래 예시를 보자
MemberService 클라이언트가 구현 클래스를 직접 선택
MemberRepository m = new MemoryMemberRepository();
- DIP 위반
- 위 상황은 MemberRepository인 추상화 인터페이스에도 의존하고있고, 객체화인 MemoryMemberRepository에도 의존하고 있다.
- 이 상황은 후에 해결하는 법을 배운다!
✅ 정리
- 객체 지향의 핵심 : 다형성
- 그러나 한계가 있다. 다형성만으로는 구현 객체를 변경할 때 클라이언트 코드도 변경되버리는 현상이 발생한다.
- 다형성 만으로는 OCP, DIP를 지킬 수 없다.
📌 객체 지향 설계와 스프링
✅ 스프링과 객체 지향이 무슨 관련일까?
- 스프링은 아래 기술들로 다형성 + OCP, DIP를 가능하게끔 지원해준다.
- DI(Dependency Injection) : 의존관계, 의존성 주입
- DI 컨테이너 제공
- 클라이언트 코드의 변경 없이 기능 확장
- 쉽게 부품을 갈아끼듯이 개발할 수 있다!
✅ 순수 자바로 좋은 객체 지향 개발을 해보기
- 순수 자바만으로 좋은 객체 지향 개발을 위해 OCP, DIP 원칙을 지키면서 개발하려 하니 너무 할일이 많다.
- 그래서 이러한 역할을 수행하는 프레임워크를 만들었다. = Spring Framework
✅ 정리
- 모든 설계에 역할과 구현을 분리하자
- 어플리케이션 설계는 공연을 설계하듯이 배역만 만들어 두고, 배우는 언제든지 유연하게 변경할 수 있도록 만들어야 한다.
- OCP, DIP 지키기
- 이상적으로는, 모든 설계에 인터페이스를 부여하자
✅ 실무에서의 고민
- 모든 설계에 인터페이스를 부여하면 좋겠지만, 인터페이스 도입에는 추상화 라는 비용이 발생한다.
- 따라서 기능을 확장할 가능성이 없다면, 구체 클래스를 직접 사용하게 된다.
- 따라서, 향후에 꼭 필요할 때 리팩토링하여 인터페이스를 도입하는 것도 또 다른 방법이다.
'Backend > Spring' 카테고리의 다른 글
[스프링 핵심 원리 - 기본편] 6. 컴포넌트 스캔 (0) | 2024.01.02 |
---|---|
[스프링 핵심 원리 - 기본편] 5. 싱글톤 컨테이너 (1) | 2024.01.01 |
[스프링 핵심 원리 - 기본편] 4. 스프링 컨테이너와 스프링 (0) | 2024.01.01 |
[스프링 핵심 원리 - 기본편] 3. 스프링 핵심 원리 이해 2 (2) | 2024.01.01 |
[스프링 핵심 원리 - 기본편] 2. 스프링 핵심 원리 이해 1 (1) | 2024.01.01 |
@Seyun. :: 개발할 결심
개발자가 되고 싶어요.