코딩일상

[nest.js] nest.js 뿌수기 공식 docs 모조리 파헤치기[providers]Constructor-based Injection vs Property-based Injection 본문

카테고리 없음

[nest.js] nest.js 뿌수기 공식 docs 모조리 파헤치기[providers]Constructor-based Injection vs Property-based Injection

solutionMan 2025. 12. 11. 21:37
반응형

1)Constructor-based Injection (기본, 권장)으로 하는게 나은경우

// cats.service.ts
@Injectable()
export class CatsService {
  constructor(
    private readonly catsRepository: CatsRepository,
    private readonly logger: LoggerService,
  ) {}

  async findAll(): Promise<Cat[]> {
    this.logger.log('Finding all cats');
    return this.catsRepository.findAll();
  }
}

// cats.controller.ts
@Controller('cats')
export class CatsController {
  constructor(
    private readonly catsService: CatsService,
    private readonly validationService: ValidationService,
  ) {}

  @Get()
  async findAll(): Promise<Cat[]> {
    return this.catsService.findAll();
  }
}

 

2)Property-based Injection 으로 하는게 나은경우

Constructor-based Injection 을 하게 되면

// base.service.ts - 기본 서비스
@Injectable()
export class BaseService {
  constructor(
    private readonly logger: LoggerService,
    private readonly config: ConfigService,
    private readonly cache: CacheService,
  ) {}

  protected log(message: string) {
    this.logger.log(message);
  }
}

// ❌ 문제: 모든 하위 클래스가 super()로 모든 의존성을 전달해야 함
@Injectable()
export class CatsService extends BaseService {
  constructor(
    private readonly catsRepository: CatsRepository,
    // 부모의 의존성도 모두 받아야 함!
    logger: LoggerService,
    config: ConfigService,
    cache: CacheService,
  ) {
    super(logger, config, cache); // 😱 번거로움!
  }

  async findAll(): Promise<Cat[]> {
    this.log('Finding all cats');
    return this.catsRepository.findAll();
  }
}

// ❌ 더 깊은 상속이면 더 끔찍해짐!
@Injectable()
export class PremiumCatsService extends CatsService {
  constructor(
    private readonly premiumRepository: PremiumRepository,
    // CatsService의 의존성
    catsRepository: CatsRepository,
    // BaseService의 의존성
    logger: LoggerService,
    config: ConfigService,
    cache: CacheService,
  ) {
    super(catsRepository, logger, config, cache); // 😱😱 악몽!
  }
}

 

 

Property-based Injection 를 사용하게되면

// base.service.ts
@Injectable()
export class BaseService {
  @Inject()
  protected readonly logger: LoggerService;

  @Inject()
  protected readonly config: ConfigService;

  @Inject()
  protected readonly cache: CacheService;

  protected log(message: string) {
    this.logger.log(message);
  }

  protected getConfig(key: string): string {
    return this.config.get(key);
  }
}

// ✅ 훨씬 깔끔!
@Injectable()
export class CatsService extends BaseService {
  constructor(
    private readonly catsRepository: CatsRepository,
  ) {
    super(); // super()만 호출하면 됨!
  }

  async findAll(): Promise<Cat[]> {
    this.log('Finding all cats'); // 부모의 logger 사용 가능
    const limit = this.getConfig('CATS_LIMIT'); // 부모의 config 사용 가능
    return this.catsRepository.findAll();
  }
}

// ✅ 더 깊은 상속도 문제없음!
@Injectable()
export class PremiumCatsService extends CatsService {
  constructor(
    private readonly premiumRepository: PremiumRepository,
  ) {
    super(null); // 자신의 의존성만 관리!
  }
  
  async findPremiumCats(): Promise<Cat[]> {
    this.log('Finding premium cats'); // BaseService의 logger 사용
    return this.premiumRepository.findAll();
  }
}
반응형
Comments