spring boot #16

·2022년 5월 15일
0

spring

목록 보기
17/22

지금까지 spring boot 기초를 공부하면서 객체를 만든 적이 없다.

spring boot가 제공하는 IoC Container에서 controller, service, repository 등의 다양한 객체를 만들고 관리해주었기 때문이다.

필요에 따라 새로운 객체가 주입될 수 있는데 그것 또한 Container에서 관리한다.

프로그래머의 코드가 아닌 외부에 의해 제어되는것을 Inversion of Control 이라고 하고,
필요한 객체를 외부에서 코드로 주입하는 것을 Dependency Injection이라고 한다.

이 두가지를 통해 더욱 유연한, 객체지향적인 코드를 만든다.


사진 출처 : https://www.youtube.com/watch?v=5d3wEN0_MLY&t=743s

🌭 IoC Container & DI

  • Inversion of Control Contaioner
  • Dependency Injection

DI가 필요한 상황을 만들고,
IoC에 객체를 등록하고 사용하는 방법을 실습해보겠다.

◾ 요구사항 변경에 취약한 코드 예시

public class Chef {
    public String cook(String menu) {
        // 재료 준비
        Pork pork = new Pork("한돈 등심");
        
        // 요리 반환
        return pork.getName() + "으로 만든 " + menu;
    }
}
class ChefTest {
    @Test
    void 돈까스_요리하기() {
        // 준비
        Chef chef = new Chef();
        String menu = "돈까스";
        // 수행
        String food = chef.cook(menu);
        // 예상
        String expected = "한돈 등심으로 만든 돈까스";
        // 검증
        assertEquals(expected, food);
    }
}
public class Pork {
    private String name;
    public Pork(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

현재 코드는 "재료"와 "셰프"의 의존성이 크다.
= 요구사항 변경에 취약한 코드 이다.

따라서 셰프와 재료 사이에 "조달 공장"을 두어 의존성을 낮추겠다.
= 요구사항 변경에 유연하도록 코드를 개선 하겠다.

◾ DI _ 의존성 주입하기

IngredientFactory ingredientFactory = new IngredientFactory();
Chef chef = new Chef(ingredientFactory);

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);
    }
public class IngredientFactory {
    public Ingredient get(String menu){
        switch (menu){
            case "돈까스":
                return new Pork("한돈 등심");
            case "스테이크":
                return new Beef("한우 꽃등심");
            case "크리스피 치킨":
                return new Chicken("국내산 닭");
            default:
                return null;
        }
    }
}
public abstract class Ingredient {
    private String name;

    public Ingredient(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

동작에 필요한 객체를 외부에서 받아왔다.

요리 메뉴가 바뀌어도 코드 변경없이 요리 가능하다.

DI를 통한 코드 개선 효과

◾ IoC Container에 객체 등록하기

IngredientFactory와 Chef 클래스의 객체를 IoC Container에 등록하기

@SpringBootTest, @Autowired

스프링 부트를 사용해서 가져오기

@SpringBootTest
class ChefTest {

    @Autowired
    IngredientFactory ingredientFactory;

    @Autowired
    Chef chef;
    
    ...
    
}

@Component

해당 클래스의 객체를 만들고, IoC Container에 객체를 등록해주는 어노테이션

@Component
public class IngredientFactory {
	...
}
.
.
.

@Component
public class Chef {
	...
}

IoC Container에서 객체를 관리해주기 때문에 아래 객체 생성 코드는 이제 필요없다.

//  IngredientFactory ingredientFactory = new IngredientFactory();
//  Chef chef = new Chef(ingredientFactory);

🌭 IoC, DI 정리

객체간 의존성이 높은 코드는 요구사항 변경에 취약하다.

따라서 외부에서 값을 삽입받는 방식인 DI 방식으로 사용하면 코드를 유연하게 작성할 수 있다.

더 나아가서 IoC Container에 필요한 객체를 등록하고 AutoWired를 통해 DI를 땡겨올 수 있었다.

0개의 댓글

관련 채용 정보