TIL/Web Back
[Sparta] 내일배움캠프 TIL 18일차
헤르로우워르드
2024. 5. 16. 23:02
3계층 구조
- 코드의 분할 방식
- Controller 파트
- Service 파트
- Repository파트
- Controller 파트 : DispatchServlet 으로부터 정보받음, HTTP 메시지를 받고 파싱, 적절한 메소드로 매핑
- Service 파트 : 로직, Controller 파트에서 dto 받음, Repository 파트로 Entity 전달
- Repository 파트 : DB와 상호작용, Service 파트에서 Entity 받음
IoC 와 DI
- 설계원칙 (IoC) 과 디자인 패턴 (DI)
들어가기 전 '의존성' 과 '주입'의 개념잡기
강한결합 - (높은 의존성)
public class Consumer {
void eat() {
Chicken chicken = new Chicken();
chicken.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.eat();
}
}
class Chicken {
public void eat() {
System.out.println("치킨을 먹는다.");
}
}
// Consumer 에서 Chicken 을 생성/초기화 하고있다
// 다른 음식을 먹기위해선 Consumer의 eat() 수정이 불가피
약한결합 - (낮은 의존성)
public class Consumer {
void eat(Food food) {
food.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.eat(new Chicken());
consumer.eat(new Pizza());
}
}
interface Food { // 인터페이스 활용!!
void eat();
}
class Chicken implements Food{
@Override
public void eat() {
System.out.println("치킨을 먹는다.");
}
}
class Pizza implements Food{
@Override
public void eat() {
System.out.println("피자를 먹는다.");
}
}
// Consumer의 eat()은 인터페이스 Food만 참조 사용중
// 인터페이스는 수정될일이 없다
주입의 종류
- 필드에 직접 주입
- 메서드를 통한 주입
- 생성자를 통한 주입
public class Consumer {
Food food;
void eat() {
this.food.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.food = new Chicken(); // 객체 food 필드를 가지고 직접초기화(주입)
consumer.eat();
consumer.food = new Pizza();
consumer.eat();
========================================================================
public class Consumer {
Food food;
...
public void setFood(Food food) {
this.food = food;
}
public static void main(String[] args) {
Consumer consumer = new Consumer();
consumer.setFood(new Chicken()); // set 메서드를 통한 초기화(주입)
consumer.eat();
consumer.setFood(new Pizza());
consumer.eat();
========================================================================
public class Consumer {
Food food;
public Consumer(Food food) {
this.food = food;
}
void eat() {
this.food.eat();
}
public static void main(String[] args) {
Consumer consumer = new Consumer(new Chicken()); // 생성자를 통한 초기화
consumer.eat();
consumer = new Consumer(new Pizza());
consumer.eat();
IoC(제어의 역전) - 주입의 흐름도
-> 결국 객체를 주입받을 필요성이 있을 때 (의존성이 필요할 때 <ex. consumer는 chiken 필요> )
자신내부에서 생성(초기화)하는 코드가 아닌 외부에서 생성후 받아오면 주입의 흐름이 바뀌어 결합도가 낮아짐
💡 마지막으로 제어의 역전은 무엇일까요?
- 이전에는 Consumer가 직접 Food를 만들어 먹었기 때문에 새로운 Food를 만들려면 추가적인 요리준비(코드변경)가 불가피했습니다.
- 그렇기 때문에 이때는 제어의 흐름이 Consumer → Food 였습니다.
- 이를 해결하기 위해 만들어진 Food를 Consumer에게 전달해주는 식으로 변경함으로써 Consumer는 추가적인 요리준비(코드변경) 없이 어느 Food가 되었든지 전부 먹을 수 있게 되었습니다.
- 결과적으로 제어의 흐름이 Food → Consumer 로 역전 되었습니다.
의존성 주입 (DI패턴) 을 통한 제어의 역전 구현!
DI패턴은 컨테이너 존재, 컨테이너의 역할은 주입해줄 객체들을 외부에서 관리하는 역할
위 코드에선 chiken, pizza, 등등의 객체들을 외부에서 생성/초기화 후 관리
필요에 따라 consumer 에게 주입해주는 기능
IoC 컨테이너 와 Bean 객체
- 컨테이너에서 Bean객체를 관리, @Component로 클래스를 Bean객체로 등록가능
Bean객체 등록시 해당 클래스의 생성/초기화는 외부에서 알아서 해줌
JPA : 스프링의 ORM (객체와 DB를 매핑시켜주는 것)