본문 바로가기
Memo

의존성 주입(DI), 의존성 역전 원칙(DIP), 제어 역전(IoC)을 TypeScript , JavaScript , Python 으로 구현한 예제를 단계별로 설명

by leopard4 2025. 3. 14.

1. 의존성 주입 (Dependency Injection)

TypeScript

// 1. 의존성 인터페이스 정의
interface ILogger {
  log(message: string): void;
}

// 2. 구체적인 구현 클래스
class ConsoleLogger implements ILogger {
  log(message: string) {
    console.log(`[Console] ${message}`);
  }
}

// 3. 의존성을 주입받는 클래스
class UserManager {
  constructor(private logger: ILogger) {}

  createUser(name: string) {
    this.logger.log(`User ${name} created`);
  }
}

// 4. 의존성 주입
const logger = new ConsoleLogger();
const userManager = new UserManager(logger);
userManager.createUser("Alice");

JavaScript (ES6)

// 1. 구체적인 구현 클래스
class ConsoleLogger {
  log(message) {
    console.log(`[Console] ${message}`);
  }
}

// 2. 의존성을 주입받는 클래스
class UserManager {
  constructor(logger) {
    this.logger = logger;
  }

  createUser(name) {
    this.logger.log(`User ${name} created`);
  }
}

// 3. 의존성 주입
const logger = new ConsoleLogger();
const userManager = new UserManager(logger);
userManager.createUser("Alice");

Python

from abc import ABC, abstractmethod

# 1. 의존성 추상 클래스
class ILogger(ABC):
    @abstractmethod
    def log(self, message: str) -> None:
        pass

# 2. 구체적인 구현 클래스
class ConsoleLogger(ILogger):
    def log(self, message: str) -> None:
        print(f"[Console] {message}")

# 3. 의존성을 주입받는 클래스
class UserManager:
    def __init__(self, logger: ILogger):
        self.logger = logger

    def create_user(self, name: str) -> None:
        self.logger.log(f"User {name} created")

# 4. 의존성 주입
logger = ConsoleLogger()
user_manager = UserManager(logger)
user_manager.create_user("Alice")

 

2. 의존성 역전 원칙 (Dependency Inversion Principle)

TypeScript

// 1. 추상화 계층 (고수준 모듈)
interface ILogger {
  log(message: string): void;
}

// 2. 저수준 모듈 (구체적 구현)
class ConsoleLogger implements ILogger {
  log(message: string) {
    console.log(`[Console] ${message}`);
  }
}

class FileLogger implements ILogger {
  log(message: string) {
    // 파일 저장 로직
    console.log(`[File] ${message}`);
  }
}

// 3. 고수준 모듈 (추상화에 의존)
class UserManager {
  constructor(private logger: ILogger) {}

  createUser(name: string) {
    this.logger.log(`User ${name} created`);
  }
}

// 4. 의존성 주입으로 구현 선택
const userManager = new UserManager(new FileLogger());
userManager.createUser("Bob");

3. 제어 역전 (Inversion of Control)

TypeScript (간단한 IoC 컨테이너)

// 1. IoC 컨테이너
class Container {
  private static dependencies: { [key: string]: any } = {};

  static register(key: string, dependency: any) {
    this.dependencies[key] = dependency;
  }

  static resolve<T>(key: string): T {
    return this.dependencies[key];
  }
}

// 2. 의존성 등록
Container.register("logger", new ConsoleLogger());
Container.register("userManager", new UserManager(Container.resolve("logger")));

// 3. 의존성 사용
const userManager = Container.resolve<UserManager>("userManager");
userManager.createUser("Charlie");

Python (간단한 IoC 컨테이너)

class Container:
    _dependencies = {}

    @classmethod
    def register(cls, key, dependency):
        cls._dependencies[key] = dependency

    @classmethod
    def resolve(cls, key):
        return cls._dependencies.get(key)

# 의존성 등록
Container.register("logger", ConsoleLogger())
Container.register("user_manager", UserManager(Container.resolve("logger")))

# 의존성 사용
user_manager = Container.resolve("user_manager")
user_manager.create_user("Charlie")

4. 핵심 원리 요약

개념
설명
예시
의존성 주입 (DI)
외부에서 의존 객체를 전달받아 결합도를 낮춥니다.
TypeScript, JavaScript, Python
의존성 역전 (DIP)
고수준 모듈이 저수준 모듈에 의존하지 않고, 추상화에 의존하도록 설계합니다.
Interface/Abstract Class 사용
제어 역전 (IoC)
객체 생성/관리를 외부 컨테이너에 위임해 제어 흐름을 역전시킵니다.
IoC 컨테이너 구현 (TypeScript 예시)