TIL/Web Back

[Sparta] 내일배움캠프 TIL 18일차

헤르로우워르드 2024. 5. 16. 23:02
3계층 구조

 

- 코드의 분할 방식

  • Controller 파트
  • Service 파트
  • Repository파트

 

  1. Controller  파트 : DispatchServlet 으로부터 정보받음, HTTP 메시지를 받고 파싱, 적절한 메소드로 매핑
  2. Service 파트 : 로직, Controller 파트에서 dto 받음, Repository 파트로 Entity 전달
  3. 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만 참조 사용중
// 인터페이스는 수정될일이 없다

 

주입의 종류

  1. 필드에 직접 주입
  2. 메서드를 통한 주입
  3. 생성자를 통한 주입
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를 매핑시켜주는 것)