의존성 주입
20강. 의존성 주입
1. 이번 강의에서 해결할 문제
Service가 파일·메일 객체를 직접 생성하면 테스트가 외부 세부에 묶입니다.
2. 학습 목표
3. 핵심 개념
DI는 컨테이너 제품이 아니라 필요한 협력자를 외부에서 받는 방식입니다. 필수 비소유 협력자는 참조로 표현할 수 있습니다.
직접 생성 버전에서 TaskService가 FileRepository, EmailNotifier, 시스템 시계를 내부에서 만들면 저장 위치와 네트워크, 현재 시간이 서비스 코드에 숨습니다. 테스트도 실제 파일과 메일에 의존합니다. DI는 이 결정을 프로그램 시작점인 조립 루트로 옮기고 서비스는 역할 계약만 사용하게 합니다.
- 참조 주입: 필수이고 Service가 소유하지 않으며 협력자가 더 오래 살아야 함
unique_ptr주입: Service가 협력자의 단독 수명을 소유함- 값 주입: 작고 복사 가능한 설정·정책
4. 가장 작은 예제로 시작하기
#include <iostream>
#include <string>
#include <string_view>
#include <vector>
struct TaskRepository {
virtual ~TaskRepository() = default;
virtual void saveCompleted(int taskId, std::string_view at) = 0;
};
struct Notifier {
virtual ~Notifier() = default;
virtual void taskCompleted(int taskId) = 0;
};
struct Clock {
virtual ~Clock() = default;
virtual std::string now() const = 0;
};
class TaskService {
TaskRepository& repo_;
Notifier& notifier_;
Clock& clock_;
public:
TaskService(TaskRepository& repo, Notifier& notifier, Clock& clock)
: repo_(repo), notifier_(notifier), clock_(clock) {}
void complete(int taskId) {
repo_.saveCompleted(taskId, clock_.now());
notifier_.taskCompleted(taskId);
}
};
struct FakeRepository final : TaskRepository {
std::vector<int> savedIds;
void saveCompleted(int taskId, std::string_view) override {
savedIds.push_back(taskId);
}
};
struct SpyNotifier final : Notifier {
std::vector<int> notifiedIds;
void taskCompleted(int taskId) override { notifiedIds.push_back(taskId); }
};
struct FixedClock final : Clock {
std::string now() const override { return "2026-07-31T10:00:00Z"; }
};
int main() {
FakeRepository repo;
SpyNotifier notifier;
FixedClock clock;
TaskService service{repo, notifier, clock};
service.complete(42);
std::cout << repo.savedIds.at(0) << ' '
<< notifier.notifiedIds.at(0) << '\n';
}
예상 출력: 42 42가 표시되어 같은 작업이 저장되고 알림됐음을 확인합니다.
5. 코드가 동작하는 이유
생성자 서명에 세 필수 협력자가 드러나므로 불완전한 TaskService를 만들 수 없습니다. 테스트는 실제 파일·메일·현재 시간 대신 Fake, Spy, FixedClock을 스택에 만들고 참조로 전달합니다. main이 더 오래 사는 협력자를 먼저 만들었으므로 Service의 참조도 유효합니다.
변경 전에는 알림 구현을 바꾸려면 Service 내부 생성을 수정합니다. 변경 후에는 조립 루트에서 SpyNotifier 대신 실제 구현을 연결하고 Service의 완료 규칙은 유지합니다. 저장 성공 뒤 알림한다는 호출 순서도 테스트할 수 있습니다.
6. 자주 하는 실수와 해결법
7. 직접 실습
8. 이해 점검 질문 3개
9. 핵심 요약
10. 다음 강의 연결
구체 구현 선택을 조립 루트로 옮겼습니다. 다음 강의에서는 이 의존 방향을 계층 전체로 확장합니다.
의존성 주입 미니 퀴즈
선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.
학습을 마쳤나요?
직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.