IoC, DI는 객체지향의 SOLID 원칙 그리고 GoF 의 디자인 패턴과 같은 설계 원칙 및 디자인 패턴입니다.
이 둘을 더 자세하게 구분해 보자면 IoC는 설계 원칙에 해당하고 DI는 디자인 패턴에 해당합니다.
어떤 객체에 스프링 컨테이너가 또 다른 객체와 의존성을 맺어주는 행위
public class Consumer {
void eat() {
// Consumer 가 직접 음식을 만들고 있음
// 제어의 흐름 Consumer → Food
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("치킨을 먹는다.");
}
}
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();
}
}
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;
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 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;
// Consumer 생성자(오버로딩)
public Consumer(Food food) {
this.food = food;
}
void eat() {
this.food.eat();
}
public static void main(String[] args) {
// Consumer class를 생성할 때 생성자를 통해 객체가 생성됨
// (Food의 구현체를 넣어줌)
// Consumer는 가만히 있고 뭐 먹고싶은지 이야기만 함!
// 제어의 흐름 Food → Consumer
// 외부(main)에서 직접 요청하는 음식을 만들어서 집어 넣는 것
// 음식을 먼저 만들고 그 만들어진 음식을 Consumer에게 집어 넣고 있다.
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("피자를 먹는다.");
}
}
💡 마지막으로 제어의 역전은 무엇일까요?
- 이전에는 Consumer가 직접 Food를 만들어 먹었기 때문에 새로운 Food를 만들려면 추가적인 요리준비(코드변경)가 불가피했습니다.
- 그렇기 때문에 이때는 제어의 흐름이 Consumer → Food 였습니다.
- 이를 해결하기 위해 만들어진 Food를 Consumer에게 전달해주는 식으로 변경함으로써 Consumer는 추가적인 요리준비(코드변경) 없이 어느 Food가 되었든지 전부 먹을 수 있게 되었습니다.
- 결과적으로 제어의 흐름이 Food → Consumer 로 역전 되었습니다.