데코레이터 패턴(Decorator Pattern)

예시 코드

// 기본 기능 정의
interface Coffee {
  getCost(): number;
  getDescription(): string;
}

// 기본 구현 
class SimpleCoffee implements Coffee {
  getCost() {
    return 10;
  }
  getDescription() {
    return "Simple coffee";
  }
}

// 데코레이터로 추가 기능을 제공한다.
class MilkDecorator implements Coffee {
  constructor(private coffee: Coffee) {}

  getCost() {
    return this.coffee.getCost() + 2;
  }
  getDescription() {
    return this.coffee.getDescription() + ", milk";
  }
}

// 데코레이터로 추가 기능을 제공한다.
class SugarDecorator implements Coffee {
  constructor(private coffee: Coffee) {}

  getCost() {
    return this.coffee.getCost() + 1;
  }
  getDescription() {
    return this.coffee.getDescription() + ", sugar";
  }
}

// 의존성 주입을 사용하여 어떤 Coffe(데코레이트 여부 필요없이)도 주입 받을 수 ㅣㅇㅆ음 
class CoffeeShop {
  constructor(private coffee: Coffee) {}

  serveCoffee() {
    console.log(`Cost: ${this.coffee.getCost()}, Description: ${this.coffee.getDescription()}`);
  }
}

// 사용 예
const simpleCoffee = new SimpleCoffee();
const milkCoffee = new MilkDecorator(simpleCoffee);
const sweetMilkCoffee = new SugarDecorator(milkCoffee);

const shop1 = new CoffeeShop(simpleCoffee);
const shop2 = new CoffeeShop(milkCoffee);
const shop3 = new CoffeeShop(sweetMilkCoffee);

shop1.serveCoffee(); // Output: Cost: $10, Description: Simple coffee
shop2.serveCoffee(); // Output: Cost: $12, Description: Simple coffee, milk
shop3.serveCoffee(); // Output: Cost: $13, Description: Simple coffee, milk, sugar

의존성 주입과, 데코레이터 패턴의 시너지

실제 사용 사례

횡단관심사와의 연관성

횡단관심사와 의존성 주입

스프링 예시

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void createUser(User user) {
        userRepository.save(user);
    }
}

횡단관심사와 의존성 주입 컨테이너(Dependency Injection Container)

스프링 예시

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void createUser(User user) {
        userRepository.save(user);
    }
}