티스토리 뷰

spring

SOLID와 Spring - 2

구삼칠오 2021. 9. 25. 14:59

Spring이 어떻게 SOLID한 프로그램을 만들도록 돕는지 살펴보기에 앞서 예제를 설정해 보겠습니다.

@Controller
public class 배고픈철수 {

    private MealService mealSerivce;

    @GetMapping("/eat")
    public 식사 meal() {
    	...
    }
}

배가고픈 client(controller) 철수는 식사를 하기 위해 식사 제공 서비스를(MealService)를 이용합니다. MealService는 다양한 메뉴로 식사를 제공하는데, MealService는 여러 업체들의 아웃소싱을 통해 메뉴를 제공 받는 다고 합니다. 그리고 각 아웃소싱 업체들은 MenuSelection이라는 정책에 맞게 메뉴를 제공해야합니다. 이러한 요구사항들은 다음과 같이 구현해볼 수 있습니다.

@Service
public class MealServiceImpl implements MealService {
    private MenuSelection menuSelection = KoreanMenuSelection();
    
    public Menu selectMenu() {
    	return menuSelection.select();
    }
}

public interface MenuSelection {
   Menu select();
}

public class KoreanMenuSelection implements MenuSelection {
    @Override
    public Menu select() { ... }
}

MealService업체는 여러 아웃소싱 업체중 한식 메뉴를 제공하는 업체를 선택해 메뉴를 제공받고 이를 Controller에게 전달합니다.

메뉴를 선택하는 클래스는 추상화가 이루어진 형태로 서비스에 제공되고 있으니 DIP를 지키고 있고, 메뉴를 선택하는 과정에 변화가 생기더라도 Service는 내부 로직에 수정이 필요하지 않으므로 OCP를 지키고 있는 나름 괜찮은 코드 같습니다.

하지만 과연 그럴까요?

 

먼저 Service는 구현 클래스를 직접 사용하고 있지 않으니 DIP를 지키고 있는 것 같습니다만, KoreanMenuSelection이 MenuSelection 타입으로 캐스팅이 되어 있을 뿐 전혀 injection이 일어나지 않고 있습니다. 즉 Service에선 interface와 구현 클래스 모두에 대한 의존성을 가지게 되는 것이지요. 또한 이런 상황에서 양식메뉴를 제공하는 업체로 변경하게 된다면, Service 코드에 변경이 생기므로 OCP도 위반하고 있다고 볼 수 있겠네요.

 

Spring은 이러한 문제를 해결하기 위해 IoC Container를 제공합니다. IoC Container는 Configuration에 등록되어 있는 Component들을 Singleton형태로 관리하며 관리되는 각 객체를 Bean이라고 부릅니다. 각 Bean객체는 ApplicationContext를 이용해 Spring으로 부터 반환 받을 수 있습니다.

 

그렇다면 IoC Container를 활용하여 코드를 변경해 보겠습니다.

 

@Service
public class MealServiceImpl implements MealService {
    private final MenuSelection menuSelection;
    
    @AutoWired
    public MealServiceImpl(MenuSelection menuSelection) {
    	this.menuSelection = menuSelection;
    }
    
    public Menu selectMenu() {
    	return menuSelection.select();
    }
}

@Configuration
public class KoreanMenuSelection implements MenuSelection {
    @Override
    public Menu select() { ... }
}

IoC Container를 활용한다면 다음과 같이 몇가지 annotation만으로 DIP와 OCP를 준수하도록 바꿀 수 있습니다. 이제 더 이상 Service는 구체 클래스에 의존하지 않으며 내부 구현 또한 알필요가 없어졌습니다.

  • KoreanMenuSelection에 @Configuration을 달아줍니다. IoC Container는 빌드 시점에 @Configuration이 붙어있는 class들을 scan하고 관리합니다.
  •  IoC가 관리하고 있는 Bean객체는 @AutoWired를 통해 주입받을 수 있습니다.
  • @AutoWired는 수정자와 필드에도 직접 사용가능합니다. (개인적으론 생성자 주입이 가장 나은 형태라고 생각합니다)

 

ref.

Robert C. Martin - Clean Arichitecture

docs.spring.io

김영한 - 스프링 핵심 원리 (기본편)

'spring' 카테고리의 다른 글

Spring Component Scan  (0) 2021.10.05
Spring IoC Container  (0) 2021.09.30
SOLID와 Spring - 1  (0) 2021.09.24
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함