ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • IoC 와 DI 용어 이해하기
    스프링 2023. 4. 15. 23:59

    IoC = 설계 원칙

    DI   =  디자인 패턴

     

    설계 원칙을 기반으로 디자인 패턴을 잘 수행하여 코드를 작성하면 좋은 코드를 만들 수 있다.

     

    좋은 코드란?

    • 논리가 간단해야 한다.
    • 중복을 제거하고 표현을 명확하게 한다.
    • 코드를 처음 보는 사람도 쉽게 이해하고 수정할 수 있어야 한다.
    • 의존성을 최소화해야 한다.
    • 새로운 기능을 추가 하더라도 크게 구조의 변경이 없어야 한다.

     

    따라서 Spring 은 개발자가 Java 를 사용하여 쉽게 좋은 코드를 작성할 수 있도록 도와주는 역할을 해줍니다.

    여기서 IoC 와 DI 는 Spring 에서 도와주는 핵심 기술 중 하나라고 할 수 있습니다.

    그리고 IoC 에 대해 ‘IoC 는 DI 로도 알려져 있다’ 라고 소개하고 있습니다.

    의역해보자면 ‘DI 패턴을 사용하여 IoC 설계 원칙을 구현하고 있다’ 라고 이해하시면 좋을 것 같습니다.

     

     

     

    이처럼 Interface 다형성의 원리를 사용하여 구현 하면 고객이 어떠한 음식을 요구하더라도 쉽게 대처할 수 있습니다.

    public class Consumer{

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

    public static void main(String[] args) {
    Consumer consumer = new Consumer();   
    consumer.eat();
    consumer.eat();
    }
    }

    interface Food{
    void eat();
    }

    class Chiken implements Food{
    @Override
    public void eat(){
    System.out.printf("치킨을 먹는다.");
    }
    }

    class Tteokbokki implements Food{
    @Override
    public void eat(){
    System.out.printf("떡볶이를 먹는다.");
    }
    }

    Food 인터페이스를 선언한 후 치킨과 떡뽂이 클래스가 Food인터페이스를 구현하고 있다.

    그리고 Consumer클래스는 Food인터페이스를 매개변수로 받아서 매개변수로 들어오는 구현체 내부에 있는 eat메서드를 실행한다. eat 메서드 내부 Food 매개변수 안에 Consumer 즉 고객이 먹고 싶어 하는 음식 클래스를 인서턴스화 하여 넘겨주면 "치킨을 먹는다.","떡뽂이를 먹는다"의 메서드가 각각 실행이 된다.

     

    이러한 관계를 약한 결합 및 약한 의존성 이라고 말할 수 있습니다.


    주입이란?

    • 우리가 주사기를 통해 백신을 우리 몸속에 주입 하듯이
    • 코드에서의 주입도 마찬가지로 여러 방법을 통해 필요로 하는 객체를 해당 객체에 전달하는 것입니다.
    • 코드를 통해 코드에서의 주입에 대해 이해해보겠습니다.

     

    필드에 직접 주입

    public class Consumer {

        Food food;

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

        public static void main(String[] args) {
            Consumer consumer = new Consumer();
            consumer.food = new Chicken();
            consumer.eat();

            consumer.food = new Tteokbokki();
            consumer.eat();
        }
    }

    interface Food {
        void eat();
    }

    class Chicken implements Food{
        @Override
        public void eat() {
            System.out.println("치킨을 먹는다.");
        }
    }

    class Tteokbokki implements Food{
        @Override
        public void eat() {
            System.out.println("떡볶이를 먹는다.");
        }
    }

    이처럼 Food 를 Consumer 에 포함 시키고 Food 에 필요한 객체를 주입하여 사용할 수 있습니다.

     

     

    메서드를 통한 주입

    public class Consumer {

        Food food;

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

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

        public static void main(String[] args) {
            Consumer consumer = new Consumer();
            consumer.setFood(new Chicken());
            consumer.eat();

            consumer.setFood(new Tteokbokki());
            consumer.eat();
        }
    }

    interface Food {
        void eat();
    }

    class Chicken implements Food{
        @Override
        public void eat() {
            System.out.println("치킨을 먹는다.");
        }
    }

    class Tteokbokki implements Food{
        @Override
        public void eat() {
            System.out.println("떡볶이를 먹는다.");
        }
    }

    이처럼 set 메서드를 사용하여 필요한 객체를 주입하여 사용할 수 있습니다.

     

    생성자를 통한 주입

    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 Tteokbokki());
            consumer.eat();
        }
    }

    interface Food {
        void eat();
    }

    class Chicken implements Food{
        @Override
        public void eat() {
            System.out.println("치킨을 먹는다.");
        }
    }

    class Tteokbokki implements Food{
        @Override
        public void eat() {
            System.out.println("떡볶이를 먹는다.");
        }
    }

    이처럼 생성자를 사용하여 필요한 객체를 주입하여 사용할 수 있습니다.

     


    제어의 역전이란?

    • 위의 예시를 통해 간단하게 설명해 보자면 인터페이스를 구현한 객체를 필요로 하는 객체에 전달하여 제어를 넘기는 것입니다.
    • 더 풀어서 설명해 보자면 기존에는 Consumer 가 직접 먹고 싶어하는 음식을 생성하여 먹었습니다.
    • 즉, 제어의 흐름이 Consumer → Food 였습니다.
    • 하지만 Interface 즉, Food 를 구현한 Chicken 객체를 Consumer 에 주입(전달)함으로써 제어의 흐름이 Food → Consumer 로 역전 되었습니다.
    • 더 깊이 있는 이해를 위해 직접 Java 로 예제를 만들어보며 이해해보겠습니다.
Designed by Tistory.