IoC & DI

이재현·2024년 8월 21일

Spring

목록 보기
6/13

🤍 IoC, DI

좋은 코드란? 간단한 논리, 중복 없는 명확한 표현 사용, 이해와 수정이 쉬워야 함 등등

좋은 코드를 작성하기 위해서는 신경 써야 하는 부분이 많다.

이를 도와주는 것이 Spring Framework이다. 그리고 이때 제공하는 핵심 기술들 중 하나가 바로 IoC와 DI이다.

IoC, DI는 객체지향의 SOLID 원칙 그리고 GoF의 디자인 패턴과 같은 설계 원칙 및 디자인 패턴이다.

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가 다른 것을 먹고 싶어할 때, 굉장히 많은 코드의 변경이 필요하게 된다.

이를 해결하기 위해서 우리는 Java Interface를 활용했다.

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

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

이와 같은 관계를 약한 결합 및 약한 의존성이라고 한다.




🩵 의존성 주입(DI, Dependency Injection)

코드에서의 주입이란 여러 방법을 통해 필요로 하는 객체를 해당 객체에 전달하는 것을 의미한다.

💙 필드에 직접 주입

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

💙 메서드를 통한 주입

public class Consumer {

Food food;

void eat() {
this.food.eat();
}
	
	// set 메서드를 통해서 필요 객체를 주입 받음
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 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();
}
}

🩵 제어의 역전(Inversion of Control)

위 코드를 잠시 보면 기존에는 Consumer가 직접 Food를 만들어서 먹었기에 새로운 Food를 만들려면 추가적인 코드 변경이 불가피했다.

이때는 제어의 흐름이 Consumer -> Food 라고 볼 수 있다.

하지만 Food Interface를 통해 이를 Consumer에게 전달해주는 식으로 변경이 됨으로써 Consumer는 추가적인 코드변경 없이 어느 Food가 오던 간에 전부 수용할 수 있게 되었다.

이때 제어의 흐름이 Food -> Consumer 라고 볼 수 있다.

이처럼 제어의 흐름이 반대가 되는 것을 제어의 역전이라 한다.




0개의 댓글