# IoC와 DI
## 미션
IoC와 DI의 개념을 설명하고, 코드 예를 통해 훈련하시오.
![홍팍-스프링-부트-입문--미션](http://drive.google.com/thumbnail?export=view&sz=w960&id=1eM_ng1Dxi14ygqYxOCRUUwLVB1jsWw4G)
## 02:10 돈가스 요리하기 테스트
#### ../main/.../ioc/Chef
```
package com.example.firstproject.ioc;
public class Chef {
public String cook(String menu) {
// 재료 준비
Pork pork = new Pork("한돈 등심");
// 요리 반환
return pork.getName() + "으로 만든 " + menu;
}
}
```
#### ../test/.../ioc/ChefTest
```
package com.example.firstproject.ioc;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class ChefTest {
@Test
void 돈가스_요리하기() {
// 준비
Chef chef = new Chef();
String menu = "돈가스";
// 수행
String food = chef.cook(menu);
// 예상
String expected = "한돈 등심으로 만든 돈가스";
// 검증
assertEquals(expected, food);
System.out.println(food);
}
}
```
#### ../main/.../ioc/Pork
```
package com.example.firstproject.ioc;
public class Pork {
private String name;
public Pork(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
```
## 05:22 스테이크 요리하기 테스트
#### ../test/.../ioc/ChefTest
```
...
class ChefTest {
...
@Test
void 스테이크_요리하기() {
// 준비
Chef chef = new Chef();
String menu = "스테이크";
// 수행
String food = chef.cook(menu);
// 예상
String expected = "한우 꽃등심으로 만든 스테이크";
// 검증
assertEquals(expected, food);
System.out.println(food);
}
}
```
#### ../main/.../ioc/Chef
```
package com.example.firstproject.ioc;
public class Chef {
public String cook(String menu) {
// 재료 준비
// Pork pork = new Pork("한돈 등심");
Beef beef = new Beef("한우 꽃등심");
// 요리 반환
// return pork.getName() + "으로 만든 " + menu;
return beef.getName() + "으로 만든 " + menu;
}
}
```
#### ../main/.../ioc/Beef
```
package com.example.firstproject.ioc;
public class Beef {
private String name;
public Beef(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
```
## 07:56 의존성 주입하기(DI) - 의존 객체를 외부에서 주입(dependency injection)
#### ../test/.../ioc/ChefTest
```
package com.example.firstproject.ioc;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class ChefTest {
@Test
void 돈가스_요리하기() {
// 준비
IngredientFactory ingredientFactory = new IngredientFactory();
Chef chef = new Chef(ingredientFactory);
String menu = "돈가스";
// 수행
String food = chef.cook(menu);
// 예상
String expected = "한돈 등심으로 만든 돈가스";
// 검증
assertEquals(expected, food);
System.out.println(food);
}
@Test
void 스테이크_요리하기() {
// 준비
IngredientFactory ingredientFactory = new IngredientFactory();
Chef chef = new Chef(ingredientFactory);
String menu = "스테이크";
// 수행
String food = chef.cook(menu);
// 예상
String expected = "한우 꽃등심으로 만든 스테이크";
// 검증
assertEquals(expected, food);
System.out.println(food);
}
}
```
#### ../main/.../ioc/Chef
```
package com.example.firstproject.ioc;
public class Chef {
private IngredientFactory ingredientFactory;
public Chef(IngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
public String cook(String menu) {
// 재료 준비
Ingredient ingredient = ingredientFactory.get(menu);
// 요리 반환
return ingredient.getName() + "으로 만든 " + menu;
}
}
```
#### ../main/.../ioc/IngredientFactory
```
package com.example.firstproject.ioc;
public class IngredientFactory {
public Ingredient get(String menu) {
switch (menu) {
case "돈가스":
return new Pork("한돈 등심");
case "스테이크":
return new Beef("한우 꽃등심");
default:
return null;
}
}
}
```
#### ../main/.../ioc/Ingredient
```
package com.example.firstproject.ioc;
public class Ingredient {
private String name;
public Ingredient(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
```
#### ../main/.../ioc/Pork
```
package com.example.firstproject.ioc;
public class Pork extends Ingredient {
public Pork(String name) {
super(name);
}
}
```
#### ../main/.../ioc/Beef
```
package com.example.firstproject.ioc;
public class Beef extends Ingredient {
public Beef(String name) {
super(name);
}
}
```
## 13:38 요구사항 변경에 유연한 확장 - 크리스피 치킨 요리하기 테스트
#### ../test/.../ioc/ChefTest
```
...
class ChefTest {
...
@Test
void 크리스피_치킨_요리하기() {
// 준비
IngredientFactory ingredientFactory = new IngredientFactory();
Chef chef = new Chef(ingredientFactory);
String menu = "크리스피 치킨";
// 수행
String food = chef.cook(menu);
// 예상
String expected = "국내산 10호 닭으로 만든 크리스피 치킨";
// 검증
assertEquals(expected, food);
System.out.println(food);
}
}
```
#### ../main/.../ioc/IngredientFactory
```
package com.example.firstproject.ioc;
public class IngredientFactory {
public Ingredient get(String menu) {
switch (menu) {
case "돈가스":
return new Pork("한돈 등심");
case "스테이크":
return new Beef("한우 꽃등심");
case "크리스피 치킨":
return new Chicken("국내산 10호 닭");
default:
return null;
}
}
}
```
#### ../main/.../ioc/Chicken
```
package com.example.firstproject.ioc;
public class Chicken extends Ingredient {
public Chicken(String name) {
super(name);
}
}
```
## 16:36 IoC 컨테이너와 DI - @SpringBootTest, @Autowired, @Component
#### ../test/.../ioc/ChefTest
```
package com.example.firstproject.ioc;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class ChefTest {
@Autowired
IngredientFactory ingredientFactory;
@Autowired
Chef chef;
@Test
void 돈가스_요리하기() {
// 준비
// IngredientFactory ingredientFactory = new IngredientFactory();
// Chef chef = new Chef(ingredientFactory);
String menu = "돈가스";
// 수행
String food = chef.cook(menu);
// 예상
String expected = "한돈 등심으로 만든 돈가스";
// 검증
assertEquals(expected, food);
System.out.println(food);
}
@Test
void 스테이크_요리하기() {
// 준비
// IngredientFactory ingredientFactory = new IngredientFactory();
// Chef chef = new Chef(ingredientFactory);
String menu = "스테이크";
// 수행
String food = chef.cook(menu);
// 예상
String expected = "한우 꽃등심으로 만든 스테이크";
// 검증
assertEquals(expected, food);
System.out.println(food);
}
@Test
void 크리스피_치킨_요리하기() {
// 준비
// IngredientFactory ingredientFactory = new IngredientFactory();
// Chef chef = new Chef(ingredientFactory);
String menu = "크리스피 치킨";
// 수행
String food = chef.cook(menu);
// 예상
String expected = "국내산 10호 닭으로 만든 크리스피 치킨";
// 검증
assertEquals(expected, food);
System.out.println(food);
}
}
```
#### ../main/.../ioc/IngredientFactory
```
package com.example.firstproject.ioc;
import org.springframework.stereotype.Component;
@Component
public class IngredientFactory {
public Ingredient get(String menu) {
switch (menu) {
case "돈가스":
return new Pork("한돈 등심");
case "스테이크":
return new Beef("한우 꽃등심");
case "크리스피 치킨":
return new Chicken("국내산 10호 닭");
default:
return null;
}
}
}
```
#### ../main/.../ioc/Chef
```
package com.example.firstproject.ioc;
import org.springframework.stereotype.Component;
@Component
public class Chef {
private IngredientFactory ingredientFactory;
public Chef(IngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
public String cook(String menu) {
// 재료 준비
Ingredient ingredient = ingredientFactory.get(menu);
// 요리 반환
return ingredient.getName() + "으로 만든 " + menu;
}
}
```
## 🔥 구글링 훈련하기
- 의존성 주입이란
- 스프링 IoC 컨테이너란
- 팩토리 패턴이란
- @Component
- 스프링 의존성 주입 방식
- 생성자 주입 vs 필드 주입