Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Tags more
Archives
Today
Total
관리 메뉴

공부하는 블로그

2024 08 16 TIL IoC와 DI 본문

내일배움캠프/TIL

2024 08 16 TIL IoC와 DI

동성만능크리너 2024. 8. 19. 13:32

스프링 관련 글들을 볼 때 많이 봤던 IoC와 DI를 공부하게 되었다. 

 

1. 좋은 코드란?

  • 논리가 간단해야함. 
  • 중복되는 코드를 제거하고 표현이 명확해야 한다. 
  • 누구나 쉽게 수정할 수 있게 가독성이 좋아야 한다. 
  • 의존성을 최소화 한다.(느슨한 결합)
  • 기능을 추가하더라도 크게 구조의 변경이 없어야 한다

IoC와 DI를 활용하면 이러한 좋은 코드를 짤 수 있다고 한다. 

 

2. 디자인 패턴과 설계 원칙

 디자인 패턴 : 소프트웨어에서 자주 발생하는 문제들을 해결하기 위한 재사용 가능한 솔루션

 설계 원칙 : 소프트웨어 시스템을 설계할 때 따라야 할 일반적인 규칙이나 가이드라인

 

여기서 IoC는 디자인 패턴이고 DI는 설계 원칙이고, DI 패턴을 사용해서 IoC 설계원칙을 구현하고 있다.

 

3. DI(Dependency Injection) : 의존성 주입

객체 지향 프로그래밍에서 객체가 자신이 의존하는 객체를 직접 생산하지 않고, 외부에서 주입받는 설계 패턴.

 

 

의존성 주입에는 크게 3가지의 주입 방식이 있다. 

 

  • 필드에 직접 주입
더보기
public class Consumer {

    Food food;

    void eat() {
        this.food.eat();
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        
        //Chicken 객체를 생성하고, Consumer의 food 필드에 주입
        consumer.food = new Chicken();
        consumer.eat(); //"치킨을 먹는다." 출력

        consumer.food = new Pizza();
        consumer.eat(); //"피자를 먹는다." 출력
    }
}

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("피자를 먹는다.");
    }
}
  • Setter를 통한 주입
더보기
public class Consumer {

    Food food;

    void eat() {
        this.food.eat();
    }
	
    //Setter
    public void setFood(Food food) {
        this.food = food;
    }

    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        //Setter를 이용한 의존성 주입
        consumer.setFood(new Chicken());
        consumer.eat();
		
        consumer.setFood(new Pizza());
        consumer.eat();
    }
}

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("피자를 먹는다.");
    }
}
  • 생성자를 통한 주입
더보기
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();
    }
}

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("피자를 먹는다.");
    }
}

 

4. IoC(Inversion of Control) : 제어의 역전

프로그램의 제어 흐름을 개발자가 아닌 프레임워크나 외부 환경에 맡기는 것.

 

 

예시코드) 

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가 직접 음식 객체를 만들어야 했기 때문에 다른 메뉴를 먹고싶으면 eat 메서드를 수정했어야 했다.

(제어의 흐름 Consumer -> food)

하지만 의존성 주입을 통해 만들어진 음식을 Consumer 객체에게 전달해주는 식으로 변경함으로써 Consumer는 따로 코드 수정 없이

어떤 음식이 되었든 그냥 의존성 주입해서 먹을 수 있게 되었다. (제어의 흐름 : food -> Consumer)