스프링 부트를 공부하면서 DI라는 말은 많이 들어보았습니다. 그런데, 정작 왜 쓰는지는 잘 몰랐습니다. 그래서, 간단하게 정리해 보고자 합니다. 혹여나, 부족한 게 있으면 덧글로 피드백 주시면 감사하겠습니다.

 


 자동차를 만들기 위해서, 바퀴가 필요하다고 해 보겠습니다. 그러면, 아래와 같은 의존 관계를 가지게 됩니다.

 

 위상 정렬하고 뭔가 유사한 거 같은 것 같은 건 기분 탓이 아닐 겁니다. 선행 후행 관계가 있으니, 유사할 수 밖에 없겠네요. 이제, 이런 상황을 생각해 봅시다. 차 한 대를 만들기 위해서, Tire interface를 implements한 Tire1을 4개 넣어야 한다고 생각해 보겠습니다. 제가 구현한 KTire, HTire, Main, Car 클래스를 보겠습니다.

 

 

 먼저, Tire 클래스입니다. toString을 오버라이드 했는데요. Tire : 반지름을 출력하게 하였습니다.

 

 

 다음에 KTire는 부모 클래스의 toString 결과물에, "K"를 덧붙입니다. KTire : 반지름의 형태로 출력됩니다. 바퀴가 4개 달린 차량들은 반지름이 5인 HTire를 쓴다고 해 봅시다.

 

 

 Car를 봅시다. 생성자만 보시면 되는데요. 조립해야 할 Tire 개수를 받습니다. 그런데, 잘 보시면, new HTire()가 있습니다. 이는, 차를 조립하는 과정에서, 타이어도 같이 만든다는 이야기입니다. 뭔가 해야 할 일이 많아진 느낌입니다. 부품을 조립하는 것 뿐만이 아니라, 부품을 같이 만들어야 합니다.

 

 8번째 줄에서, 바퀴 부품을 만들었습니다. new HTire()를 보면 알 수 있습니다.

 

 

  바깥에서는, 그냥 차를 조립하는 데 필요한 바퀴의 개수만 받고 있어요. 보통은 4개일 것이니, n 값을 4로 해서 생성자에 넘겼습니다.

 

 결과는 위와 같아요. 이제 요구 사항을 바꿔보도록 하겠습니다.

 


 필요한 바퀴 수가 12개인 차량들은, 앞에 4개는 반지름이 5인 KTire를 써야 하고, 나머지 뒤에 8개는 반지름이 5인 HTire를 써야 해요.

 

 요구 사항에 따라 Car를 바꾸면 요래 될 겁니다. 요구 사항이 하나 더 추가 되었는데도 간단하지 않은 거 같네요.

 

 이제 프로그램을 돌려 봅시다.

 

 잘 동작하긴 합니다. 그런데, 차를 조립할 때, 바퀴 같은 부품을 같이 만드는 게 좋은 선택일까요? 이미 만들어진 부품들을 받는 것이 더 나은 방법이지 않을까요? 차를 조립할 때에는 이미 만들어진 부품들을 잘 조립하는 일만 하면 됩니다. 부품들을 같이 만들 것이 아니라.

 

 

 즉, 위 예제에서는 Car를 생성할 때, Tire도 제작하고, 배열하고, 조립하는 역할 3개가 같이 들어가 있었습니다. 이것을 아래와 같이 바꿔 봅시다. 제작하고 배열하는 건 바깥 클래스에서 하고, Car 클래스에서는 조립만 하도록 하겠습니다.

 

 위와 같이 바꿔 보겠습니다. Car에서는 이미 만들어진 바퀴와, 순서도를 가지고 조립만 하게 됩니다.

 


 차를 만드는 데 필요한 것은 바퀴들의 List이므로, Main에서 바퀴들을 모두 만들고, List에 넣습니다.

 

 6번째 줄부터 7번째 줄까지는 바퀴 4개짜리 자동차의 바퀴들을 생성하고 배열한 것입니다. 다음에, 10번째부터 13번째 줄까지는 바퀴 12개짜리 자동차의 바퀴들을 생성하고 배열한 것입니다. 이것을 Car 클래스의 생성자가 아니라 Car의 바깥 클래스인 Main에서 합니다.

 

 

 그러면, Car 클래스의 생성자에서는, tires의 배열 정보를 가지고 조립하기만 하면 됩니다. 위와 같은 방법을 생성자 주입이라고 합니다. 여기서 중요한 것은, 이렇게 해서 Car 생성자에서 타이어를 만들고, 배열하는 일을 하지 않아도 된다는 것입니다. 해야 하는 일을 분리했다는 것이 중요합니다.

 

 제가 만든 가희와 자원놀이 문제는, 게임 상태를 카드 덱, 자원의 점유 상태 정도로 표현할 수 있을 겁니다. 게임 상태는, 카드 덱을 필요로 하니, 의존성 주입을 통해서 구현하면 됩니다. 구현한 코드는 여기에 있습니다.