본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 11. 4. · 333 Views
Dependency Injection 기초부터 심화까지
의존성 주입(DI)의 핵심 개념부터 고급 패턴까지 실전 예제로 학습합니다. 생성자 주입, 인터페이스 분리, IoC 컨테이너 활용법을 다룹니다.
들어가며
이 글에서는 Dependency Injection 기초부터 심화까지에 대해 상세히 알아보겠습니다. 총 12가지 주요 개념을 다루며, 각각의 개념에 대한 설명과 실제 코드 예제를 함께 제공합니다.
목차
- 기본_의존성_주입_개념
- 인터페이스_기반_주입
- 싱글톤_패턴과_DI
- 팩토리_패턴_DI
- 프로퍼티_주입_패턴
- DI_컨테이너_기본
- 자동_의존성_해결
- 스코프_관리_패턴
- 생성자_주입_vs_메서드_주입
- 순환_의존성_해결
- 모듈_기반_DI_시스템
- 고급_인터셉터_패턴
1. 기본 의존성 주입 개념
개요
클래스가 필요한 의존성을 외부에서 주입받는 기본 패턴입니다. 결합도를 낮추고 테스트를 용이하게 만듭니다.
코드 예제
class Logger {
log(message: string) { console.log(message); }
}
class UserService {
constructor(private logger: Logger) {}
createUser(name: string) {
this.logger.log(`User ${name} created`);
}
}
const service = new UserService(new Logger());
설명
UserService가 Logger를 생성자를 통해 주입받아 사용합니다. 의존성이 외부에서 관리되어 코드 재사용성이 높아집니다.
2. 인터페이스 기반 주입
개요
인터페이스를 통해 구체적인 구현체를 추상화하여 더 유연한 설계를 만듭니다.
코드 예제
interface ILogger {
log(message: string): void;
}
class ConsoleLogger implements ILogger {
log(msg: string) { console.log(msg); }
}
class FileLogger implements ILogger {
log(msg: string) { /* 파일에 저장 */ }
}
class UserService {
constructor(private logger: ILogger) {}
}
설명
ILogger 인터페이스를 사용해 ConsoleLogger나 FileLogger를 자유롭게 교체할 수 있습니다. 개방-폐쇄 원칙을 준수합니다.
3. 싱글톤 패턴과 DI
개요
싱글톤 인스턴스를 의존성으로 주입하여 전역 상태를 안전하게 관리합니다.
코드 예제
class Database {
private static instance: Database;
private constructor() {}
static getInstance(): Database {
if (!this.instance) {
this.instance = new Database();
}
return this.instance;
}
}
const db = Database.getInstance();
설명
Database 클래스는 단 하나의 인스턴스만 생성되며, getInstance()를 통해 동일한 인스턴스를 공유합니다.
4. 팩토리 패턴 DI
개요
팩토리 함수를 주입하여 객체 생성 로직을 캡슐화하고 런타임에 다양한 타입을 생성합니다.
코드 예제
interface INotification { send(msg: string): void; }
type NotificationFactory = (type: string) => INotification;
class NotificationService {
constructor(private factory: NotificationFactory) {}
notify(type: string, msg: string) {
const notification = this.factory(type);
notification.send(msg);
}
}
설명
팩토리 함수를 주입받아 필요한 타입의 알림 객체를 동적으로 생성합니다. 객체 생성 로직이 분리됩니다.
5. 프로퍼티 주입 패턴
개요
생성자가 아닌 프로퍼티를 통해 의존성을 주입하는 방식입니다. 선택적 의존성에 유용합니다.
코드 예제
class UserService {
logger?: ILogger;
setLogger(logger: ILogger) {
this.logger = logger;
}
createUser(name: string) {
this.logger?.log(`Creating ${name}`);
}
}
const service = new UserService();
service.setLogger(new ConsoleLogger());
설명
setLogger()를 통해 나중에 의존성을 주입할 수 있습니다. 순환 참조 문제를 해결할 때도 활용됩니다.
6. DI 컨테이너 기본
개요
DI 컨테이너는 의존성 등록과 해결을 자동화하는 핵심 도구입니다.
코드 예제
class DIContainer {
private services = new Map<string, any>();
register(name: string, instance: any) {
this.services.set(name, instance);
}
resolve<T>(name: string): T {
return this.services.get(name);
}
}
const container = new DIContainer();
container.register('logger', new ConsoleLogger());
설명
컨테이너에 서비스를 등록하고 필요할 때 resolve()로 가져옵니다. 의존성 관리가 중앙화됩니다.
7. 자동 의존성 해결
개요
메타데이터를 활용해 의존성을 자동으로 주입하는 고급 패턴입니다.
코드 예제
const Injectable = () => (target: any) => {
target.injectable = true;
};
@Injectable()
class ApiService {
constructor(private http: HttpClient) {}
}
function autoResolve<T>(Class: new (...args: any[]) => T): T {
// 생성자 파라미터 자동 해결
return new Class(/* auto resolved deps */);
}
설명
데코레이터를 사용해 클래스를 주입 가능하게 표시하고, 컨테이너가 자동으로 의존성을 해결합니다.
8. 스코프 관리 패턴
개요
의존성의 생명주기를 Singleton, Transient, Scoped로 관리합니다.
코드 예제
enum Scope { Singleton, Transient, Scoped }
class Container {
register(name: string, factory: () => any, scope: Scope) {
if (scope === Scope.Singleton) {
const instance = factory();
return () => instance;
}
return factory; // Transient
}
}
container.register('db', () => new Database(), Scope.Singleton);
설명
Singleton은 하나의 인스턴스를 공유하고, Transient는 매번 새로 생성합니다. 리소스 관리가 최적화됩니다.
9. 생성자 주입 vs 메서드 주입
개요
필수 의존성은 생성자로, 선택적 의존성은 메서드로 주입하는 하이브리드 패턴입니다.
코드 예제
class OrderService {
constructor(private db: Database) {} // 필수
private emailService?: EmailService;
setEmailService(service: EmailService) { // 선택
this.emailService = service;
}
createOrder() {
this.db.save(/* ... */);
this.emailService?.sendConfirmation();
}
}
설명
필수 의존성은 생성자로 강제하고, 선택적 기능은 메서드로 주입하여 유연성을 확보합니다.
10. 순환 의존성 해결
개요
Provider 패턴을 활용해 순환 참조 문제를 우아하게 해결합니다.
코드 예제
class ServiceA {
private serviceB?: ServiceB;
setServiceB(b: ServiceB) {
this.serviceB = b;
}
}
class ServiceB {
constructor(private serviceA: ServiceA) {}
}
const a = new ServiceA();
const b = new ServiceB(a);
a.setServiceB(b);
설명
한쪽은 생성자 주입, 다른 쪽은 세터 주입을 사용해 순환 참조를 끊습니다. 의존성 그래프가 명확해집니다.
11. 모듈 기반 DI 시스템
개요
관련된 의존성을 모듈로 그룹화하여 대규모 애플리케이션을 구조화합니다.
코드 예제
class AppModule {
static providers = [
{ provide: 'Logger', useClass: ConsoleLogger },
{ provide: 'Database', useClass: PostgresDB },
];
static create() {
const container = new DIContainer();
this.providers.forEach(p =>
container.register(p.provide, new p.useClass())
);
return container;
}
}
설명
모듈이 관련 서비스를 묶어 등록하고, 애플리케이션 전체 의존성을 체계적으로 관리합니다.
12. 고급 인터셉터 패턴
개요
의존성 호출을 가로채서 로깅, 캐싱, 에러 핸들링 등을 추가하는 AOP 스타일 패턴입니다.
코드 예제
function createProxy<T extends object>(target: T): T {
return new Proxy(target, {
get(obj, prop) {
const original = obj[prop as keyof T];
if (typeof original === 'function') {
return (...args: any[]) => {
console.log(`Calling ${String(prop)}`);
return original.apply(obj, args);
};
}
return original;
}
});
}
설명
Proxy를 사용해 메서드 호출을 가로채고 추가 로직을 투명하게 실행합니다. 횡단 관심사를 분리합니다.
마치며
이번 글에서는 Dependency Injection 기초부터 심화까지에 대해 알아보았습니다. 총 12가지 개념을 다루었으며, 각각의 사용법과 예제를 살펴보았습니다.
관련 태그
#TypeScript #DependencyInjection #DesignPatterns #SOLID #IoC
이 카드뉴스가 포함된 코스
댓글 (0)
함께 보면 좋은 카드 뉴스
마이크로서비스 배포 완벽 가이드
Kubernetes를 활용한 마이크로서비스 배포의 핵심 개념부터 실전 운영까지, 초급 개발자도 쉽게 따라할 수 있는 완벽 가이드입니다. 실무에서 바로 적용 가능한 배포 전략과 노하우를 담았습니다.
Application Load Balancer 완벽 가이드
AWS의 Application Load Balancer를 처음 배우는 개발자를 위한 실전 가이드입니다. ALB 생성부터 ECS 연동, 헬스 체크, HTTPS 설정까지 실무에 필요한 모든 내용을 다룹니다. 초급 개발자도 쉽게 따라할 수 있도록 단계별로 설명합니다.
고객 상담 AI 시스템 완벽 구축 가이드
AWS Bedrock Agent와 Knowledge Base를 활용하여 실시간 고객 상담 AI 시스템을 구축하는 방법을 단계별로 학습합니다. RAG 기반 지식 검색부터 Guardrails 안전 장치, 프론트엔드 연동까지 실무에 바로 적용 가능한 완전한 시스템을 만들어봅니다.
에러 처리와 폴백 완벽 가이드
AWS API 호출 시 발생하는 에러를 처리하고 폴백 전략을 구현하는 방법을 다룹니다. ThrottlingException부터 서킷 브레이커 패턴까지, 실전에서 바로 활용할 수 있는 안정적인 에러 처리 기법을 배웁니다.
AWS Bedrock 인용과 출처 표시 완벽 가이드
AWS Bedrock의 Citation 기능을 활용하여 AI 응답의 신뢰도를 높이는 방법을 배웁니다. 출처 추출부터 UI 표시, 검증까지 실무에서 바로 사용할 수 있는 완전한 가이드입니다.