[Spring] Spring 기본개념 (IoC와 DI, 객체지향 4대원칙, SOLID 등)
서버개발

[Spring] Spring 기본개념 (IoC와 DI, 객체지향 4대원칙, SOLID 등)

 

공부하면서 정리한 것이라 난잡할 수 있습니다.

 

※참고※

김영한의 스프링 핵심원리 기본편과 여러 블로그들을 참고하여 작성합니다.

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보세요! 📢

www.inflearn.com

스프링 핵심 개념

# 자바 언어 기반(객체지향)
# 객체 지향의 강력한 특징을 살림 (좋은 객체 지향을 하도록)
# 객체 지향 -> 유연하고 변경이 용이함

객체지향 4대 특성

# 추상화
- 다형성, 상속 모두 추상화에 속하는 개념 

# 캡슐화
- 단순 호출만으로 해당 기능을 실행할 수 있고 이를 통해 객체 단위 프로그램 설계 가능
- 재 사용성 향상 ( 단일 객체에만 영향을 줌, 모듈성과 응집도 증가 )
- 메소드에서 확인 후 실행하는 것이 기본 원칙으로 무결성 보장
> Getter / Setter ( 외부에서 내부 속성을 직접 접근해서는 안됨 ) 
> 실물 객체가 가진 모든 기능을 제공하여야 함
> 객체 안의 메소드는 객체 안의 속성을 처리해야 함 ( 외부 변수 ㄴㄴ )
> CRUD


# 상속 
- 객체지향에서의 상속은 하위로 내려 갈수록 구체화 되는 것을 의미
- 최상위 구조를 보고 하위 클래스 이해 가능 / 재사용성 향상 ( 필요한 메소드를 항상 재생성하지 않고 상속받아 사용 ) 
/ 확장성 향상 ( 하위 객체를 만드는게 쉬워짐 ) / 유지보수성 향상 ( 각 객체마다 일관된 형태 )

# *다형성 
- 같은 이름의 메소드를 통해 각자의 객체에 맞는 여러 형태의 다른 기능을 구현 가능 ( 오버로딩, 오버라이딩 )
- 오버로딩 : 메서드명 동일, 매개변수 및 타입 다름, 리턴 타입 관계없음 ( 거의 동일한 기능을 하는 메서드를 재정의 하는 것 )
*매개변수는 같고 리턴 타입만 다르면 오버로딩이 성립되지 않는다.
- 오버라이딩 : 메서드명 동일, 매개변수 및 타입 동일, 리턴 타입 동일 ( 상속받은 기존의 메서드를 재정의 하는 것 )
*다형성으로 인터페이스를 구현한 객체를 실행 시점에 유연하게 변경할 수 있다.

 

# 다형성의 본질
- 인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경 가능
- 다형성의 본질을 이해하려면 협력이라는 객체 사이의 관계에서 시작
- *클라이언트를 변경하지 않고, 서버의 구현 기능을 유연하게 변경
- 인터페이스를 안정적으로 잘 설계하는 것이 중요 ( usb 모양이 바뀐다면?, 자동차 조종법이 바뀐다면? )

# 역할과 구현
- 운전자가 차가 달라져도 운전가능 ( 자동차 구조를 몰라도 됌 ) -> 자동차 세상을 무한히 확장 가능
운전자(클라이언트)를 바꿀필요없이 새로운 자동차를 생산가능(역할과 구현을 구분해서 가능한 일)
- 로미오 역할(배우가 바뀌어도 됨)
로미오(클라이언트) <-> 줄리엣(서버) 서로 관여하지않음

# 역할과 구현을 분리 (단순, 유연, 변경 편리)
- 클라이언트는 대상의 역할(인터페이스)만 알면 된다
- 클라이언트는 구현 대상의 내부 구조를 몰라도 된다.
- 클라이언트는 구현 대상의 내부 구조가 변경되어도 영향을 받지 않는다.
- 클라이언트는 구현 대상 자체를 변경해도 영향을 받지 않는다.
- 역할 - 인터페이스 / 구현 - 인터페이스를 구현한 클래스, 구현 객체
- 클라이언트 : 요청, 서버 : 응답 ( 서로 협력 관계 )

스프링과 객체지향

# 다형성이 가장 중요한 개념
# 객체지향적 특성을 극대화할 수 있게 도와줌
# 제어의 역전(IoC), 의존관계 주입(DI)


# IoC ( Inversion of Control ) 
- IoC(Inversion of Control)란 "제어의 역전" 이라는 의미로, 말 그대로 메소드나 객체의 호출작업을 개발자가 결정하는 것이 아니라, 외부에서 결정되는 것을 의미한다.
- 객체의 의존성을 역전시켜 객체 간의 결합도를 줄이고 유연한 코드를 작성할 수 있게 하여 가독성 및 코드 중복, 유지 보수를 편하게 할 수 있게 한다.
-  IoC는 객체 생명 관리, 흐름 제어를 제 3자에게 위임하는 프로그래밍 모델입니다. 디자인 패턴인 템플릿 메소드 패턴에서도 IoC 개념을 찾아 볼 수 있다.

기존에는 다음과 순서로 객체가 만들어지고 실행되었다.
1. 객체 생성 2. 의존성 객체 생성 3. 클래스 내부에서 생성 4. 의존성 객체 메소드 호출

스프링에서는 다음과 같이 작동한다.
1. 객체 생성 2. 의존성 객체 주입 ( 제어권을 스프링에게 위임, 스프링이 만든 객체를 주입 ) 3. 의존성 객체 메소드 호출

# 스프링이 모든 의존성 객체를 스프링이 실행될 때 만들어 필요한 곳에 주입시킴으로써 Bean들은 싱글톤 패턴의 특징을 갖는다.
# 객체 생명 주기를 직접 관리하게 된다면? 
1. 도메인 모델 상 객체 삭제가 불가능 하더라도 개발자가 핸들링이 가능하기 때문에 개발자에게 권한이 너무 많다 ( 캡슐화 위반 )
2. 객체가 많아질 경우 개발자는 모든 객체의 구조를 모두 알고있어야 한다 ( 요구사항이 변하기 때문 )

# DI ( Dependency Injection )
- DI는 IoC 프로그래밍 모델을 구현하는 방식중에 하나이다.
- DI(Dependency Injection)란 스프링이 다른 프레임워크와 차별화되어 제공하는 의존 관계 주입 기능으로,
객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입 시켜주는 방식이다.
- *DI는 오브젝트 레퍼런스를 외부로부터 제공(주입)받고 이를 통해 여타 오브젝트와 다이나믹하게 의존관계가 만들어지는 것이 핵심
( 객체 참조를 외부로부터 받아 다른 객체와 동적으로 의존관계가 만들어지는 것 )
- DI를 통해 모듈 간의 결합도가 낮아지고 유연성이 높아진다.
- 클라이언트 코드를 변경하지 않고도 소스의 변경이 가능하다.
ex ) A p = new B( ); <- 일반적인 생성 ( A와 B는 상속 관계 ) 
DI란 이렇게 직접 생성하는 것이 아닌 외부(IoC 컨테이너)에서 생성된 B 객체를 주입시켜 setter 혹은 생성자를 통해 사용하는 방식
- 스프링에서는 객체를 Bean이라고 부르며, Bean 컨테이너에서 객체를 생성해준다.

# *의존성이란?
- 서로 다른 객체간에 레퍼런스 참조가 되어있다는 말이다.
- A -> B간에 의존 관계에 있을 때, B 객체에 변경사항이 생겨 A 객체가 영향을 받는 구조인 것

public class A {

     private B b = new B();

     public void method() {
         b.something();
     }
}


# *주입이란?
- 외부로부터 객체의 레퍼런스 값을 전달 받게 되어 객체가 참조 되어지는 방식이다.

# 의존성 주입이란?
- 의존관계에 있는 객체들이 외부에서 객체의 레퍼런스를 전달하여 사용하고자 하는 객체에서 코드를 작성할 수 있게 한다.

# DI의 세가지 조건 
- 클래스 모델이나 코드에는 런타임 시점의 의존관계가 드러나지 않는다. 그러기 위해서는 인터페이스에만 의존하고 있어야 한다.
- 런타임 시점의 의존관계는 컨테이너나 팩토리 같은 제3의 존재가 결정한다.
- 의존관계는 사용할 오브젝트에 대한 레퍼런스를 외부에서 제공(주입)해줌으로써 만들어진다.
- 외부로부터 인터페이스타입으로 얼마든지 부품이 교체 될 수 있으니 코드가 유연해 진다. 
또한 의존성 제어로 인해 수많은 객체들에 의존관계를 맺어주고 개발하는 클라이언트 입장에서는 편하게 비지니스로직에 집중할 수 있다. 
이러한 DI를 잘 녹인 프레임워크가 스프링.
- *핵심은 DI는 클래스타입이 고정되어 있지 않고 인터페이스 타입의 파라미터를 통해 다이나믹하게 구현 클래스를 결정해서 제공 받을수 있어야 한다.

객체지향 5대 원칙

# SRP 단일 책임 원칙
- 한 클래스는 하나의 책임만
- 변경에 파급효과가 적어야 한다

# *OCP : 개방 폐쇄 원칙
- 확장에는 열려있으나 변경에는 닫혀있어야한다.
- 확장(인터페이스를 통한 새로운 클래스 생성), 변경(인터페이스 변경)
-> 문제점 : 구현 객체를 변경하려면 클라이언트 코드를 바꿔야함(다형성을 사용했지만 OCP를 어김)
-> 객체 생성과 연관관계를 맺어주는 조립, 설정자가 필요 (IoC, DI)

# Liskov 치환 원칙
- 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스를 바꿀 수 있어야 함
(엑셀은 앞으로 가는 기능인데 뒤로 가는 차가 나왔더라도 뒤로 가게 만들면 안됨)

# ISP 인터페이스 분리 원칙
- 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다
(자동차의 운전과 정비의 인터페이스를 나누면, 정비의 인터페이스를 수정해도 운전 인터페이스에 영향x)

# *DIP 의존관계 역전 원칙
- 추상화에 의존, 구체화에 의존 X
(역할과 구현을 철저히 분리.. 인터페이스에 의존해야한다.)
-> 클라이언트가 인터페이스에 의존해야 유용함
ex) Class A = new ClassChildA() -> DIP 위반
> 자신보다 변하기 쉬운것에 의존하지 않아야 한다.

- 다형성만으로는 OCP DIP를 지킬 수 없다 . .  그래서 DI를 사용
# DI -> 의존관계 / 의존성 주입 클라이언트의 코드의 변경 없이 기능 확장이 목표

Spring 시작 전 알아야할 것

# 모든 설계에 역할과 구현을 분리하자
# 최대한 많은 설계에 인터페이스를 부여하자
# 최대한 변경이 없게 유연하게 변경 가능하도록 한다.
# 인터페이스 도입 시 추상화라는 비용이 발생
- 기능 확장 가능성이 없다면 구체 클래스를 직접 사용하고, 향후 리팩토링을 통해 인터페이스를 도입하는것도 됨

 

 

 

 

#서버 #Spring 기초원리 #객체지향 4원칙 #SOLID # 객체지향 SOLID #Spring 개념 #Spring이란 #DI #IoC #의존성주입 #제어권역전