IoC 설계원칙-제어의 역전 ,DI 디자인 패턴-의존성 주입 - 1탄

Terror·2024년 8월 12일

사전적 정의

  • IoC DI 는 객체지향의 SOLID 원칙 그리고 GoF의 디자인 패턴과 같은 설계 원칙 및 디자인 패턴이다
    • SOLID :
      • S : SRP (단일책임의 원칙 : Single Responsibility Principle)
      • O : OCP (개방폐쇄의 원칙 : Open Close Principle)
      • L : LSP (리스코브 치환의 원칙 : The Liskov Substitution Principle)
      • I : ISP (인터페이스 분리의 원칙 : Intrerface Segregation Principle)
      • D : DIP (의존성역전의 원칙 : Dependecy Inversion Principle)
    • GoF :
      • 생성,구조,행동 3가지로 나누는 디자인 패턴 (자세한 내용은 참조블로그)
  • 조금 더 자세히 구분해보자면, IoC = 설계원칙 DI = 디자인 패턴 에 해당
  • 생활에 익숙한 요리에 비교해 보자

김치 볶음밥 맛있게 만드는 방법 (IoC)

💡 맛있는 김치 볶음밥을 만들기 위한 원칙
  • 신선한 재료를 사용한다.
  • 신 김치를 사용한다.
  • 밥과 김치의 비율을 잘 맞춰야 한다.
  • 볶을 때 재료의 순서가 중요하다.

김치 볶음밥 레시피 (DI)

💡 맛있는 김치 볶음밥을 만들기 위한 황금 레시피
  1. 오일을 두른 팬에 채썬 파를 볶아 파기름을 만든다.
  2. 준비한 햄을 넣고 볶다가, 간장 한스푼을 넣어 풍미를 낸다.
  3. 설탕에 버무린 김치를 넣고 함께 볶는다.
  4. 미리 식혀 둔 밥을 넣어 함께 볶는다.
  5. 참기름 한스푼을 넣어 마무리한다.

  • 상단의 내용은 Spring Docs에서 발췌해온 내용이다
  • IoC에 대해 “IoC는 DI로도 알려져 있다” 라고 소개하고 있으며
  • 의역하면, “DI 패턴을 사용하여 IoO 설계 원칙을 구현하고 있다” 라고 이해 가능하다

의존성

강하게 결합 되는 의존성

  • 백문이 불여일코(드), 코드로 봐보자
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("치킨을 먹는다.");
    }
}
  • 만일 저기서 치킨이 아닌,햄버거가 먹고싶다면 아래와같이 코드가 변경될것이다
package Consumer;

public class Consumer {

    void eat() {
        Hamburger hamburger = new Hamburger(); //1
        hamburger.eat(); //2
    }

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

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

class Hamburger { //3 클래스 추가
    public void eat() {
        System.out.println("햄버거를 먹는다.");
    }
}
  • 1,2 번의 코드자리가 변경되므로, 많은 수의 코드변경이 불가피하다고 볼 수 있다
  • 그래서 우리는 이런 코드를 “강하게 결합” 되어 있다고 할 수 있다

약하게 결합 되는 의존성

package Consumer;

public class Consumer {

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

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

interface Food {
    void eat();
}

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

class Hamburger implements Food {
    @Override
    public void eat() {
        System.out.println("햄버거를 먹는다.");
    }
}
  • 위 코드는 단순히 Hamburger 클래스만 추가해주어, 다형성을 활용하여 처리 하고 있는 모습이다

주입

  1. 필드 직접 주입
  2. 메서드를 통한 주입
  3. 생성자를 통한 주입

제어의 역전 (IoC)

  1. 강한결합 - ConsumerFood
  2. 약한결합 - FoodConsumer
  3. 조금더 요리에 맞게 설명해보면
    • 이전(강한결합)에는 Consumer 가 직접 Food를 만들어 먹었기 때문에 (아래코드)
      void eat() {
          Hamburger hamburger = new Hamburger(); //1
          hamburger.eat(); //2
      }
      • Food를 만들기위한 코드변경이 불가피하였다
    • 하지만 FoodConsumer 에게 전달 해주는식
      void eat(Food food) {
          food.eat();
      }
      • 으로 변경됨에 따라 코드변경없이, 어느 Food가 되었든지 전부 먹기 가능
  4. 이로써 제어의 역전 (FoodConsumer) 로 역전되었다고 볼 수 있다

참조 블로그

SOLID : https://www.nextree.co.kr/p6960/

GoF : https://4z7l.github.io/2020/12/25/design_pattern_GoF.html

profile
테러대응전문가

0개의 댓글