📁기타

[디자인 패턴] 3가지 디자인 패턴으로 TypeScript 코드 작성해보기

윤찬님 2023. 12. 22. 10:44

옵저버 패턴

 

: 옵저버(관찰자)들이 관찰하고 있는 대상자의 상태가 변화가 있을 때마다 대상자는 직접 목록의 각 관찰자들에게 통지하고 관찰자들은 알림을 받아 조치를 취하는 행동 패턴이다.

 

interface CafeObserver {
  update(customerName: string, orderedItem: string): void;
}

class CustomerObserver implements CafeObserver {
  public update(customerName: string, orderedItem: string): void {
    console.log(`${customerName}님이 ${orderedItem}을(를) 주문했습니다.`);
  }
}

// 카페
class Cafe {
  private observers: CafeObserver[] = [];

  // 옵저버 등록
  public addObserver(observer: CafeObserver): void {
    this.observers.push(observer);
  }

  // 옵저버 제거
  public removeObserver(observer: CafeObserver): void {
    this.observers = this.observers.filter((o) => o !== observer);
  }

  // 주문 알림
  public notifyObservers(customerName: string, orderedItem: string): void {
    this.observers.forEach((observer) => observer.update(customerName, orderedItem));
  }

  // 주문 처리
  public placeOrder(customerName: string, orderedItem: string): void {
    // 주문 처리 로직...

    // 옵서버들에게 주문 알림
    this.notifyObservers(customerName, orderedItem);
  }
}

// 사용 예시
const customerObserver1 = new CustomerObserver();
const customerObserver2 = new CustomerObserver();

const cafe = new Cafe();

// 옵저버 등록
cafe.addObserver(customerObserver1);
cafe.addObserver(customerObserver2);

// 주문 시뮬레이션
cafe.placeOrder('사람1', '아메리카노');
cafe.placeOrder('사람2', '카페라떼');

 

 

 

팩토리 메서드 패턴

 

: 객체의 생성을 서브 클래스에서 결정하도록 하는 패턴. 생성 패턴 중 하나로, 객체 생성을 처리하는 데 필요한 인터페이스를 정의하고 이를 구현하는 구상 클래스에서 실제 객체의 생성을 담당한다.

 

// 동물 인터페이스
interface Animal {
  makeSound(): void;
}

// 구체적인 동물 클래스들
class Dog implements Animal {
  makeSound(): void {
    console.log("멍멍");
  }
}

class Cat implements Animal {
  makeSound(): void {
    console.log("야옹");
  }
}

// 팩토리 인터페이스
interface AnimalFactory {
  createAnimal(): Animal;
}

// 구체적인 팩토리 클래스들
class DogFactory implements AnimalFactory {
  createAnimal(): Animal {
    return new Dog();
  }
}

class CatFactory implements AnimalFactory {
  createAnimal(): Animal {
    return new Cat();
  }
}

// 사용 예시
const dogFactory: AnimalFactory = new DogFactory();
const catFactory: AnimalFactory = new CatFactory();

const myDog: Animal = dogFactory.createAnimal();
myDog.makeSound(); // 출력: 멍멍

const myCat: Animal = catFactory.createAnimal();
myCat.makeSound(); // 출력: 야옹

 

스트레티지 패턴

 

알고리즘을 정의하고 해당 알고리즘을 캡슐화하여 서로 교환 가능한 알고리즘 패밀리를 만들 수 있게 해준다. 스트레티지 패턴을 사용하면 알고리즘의 변경이나 확장이 간단해지며, 코드의 재사용성과 유지보수성이 향상된다.

 

// 전략 인터페이스
interface MathOperation {
  calculate(num1: number, num2: number): number;
}

// 덧셈 전략
class Addition implements MathOperation {
  calculate(num1: number, num2: number): number {
    return num1 + num2;
  }
}

// 뺄셈 전략
class Subtraction implements MathOperation {
  calculate(num1: number, num2: number): number {
    return num1 - num2;
  }
}

// 곱셈 전략
class Multiplication implements MathOperation {
  calculate(num1: number, num2: number): number {
    return num1 * num2;
  }
}

// 계산기 컨텍스트
class Calculator {
  private strategy: MathOperation;

  constructor(strategy: MathOperation) {
    this.strategy = strategy;
  }

  setStrategy(strategy: MathOperation): void {
    this.strategy = strategy;
  }

  calculate(num1: number, num2: number): number {
    return this.strategy.calculate(num1, num2);
  }
}

// 사용 예시
const additionStrategy: MathOperation = new Addition();
const subtractionStrategy: MathOperation = new Subtraction();
const multiplicationStrategy: MathOperation = new Multiplication();

const calculator = new Calculator(additionStrategy);

console.log(calculator.calculate(5, 3)); // 출력: 8

calculator.setStrategy(subtractionStrategy);
console.log(calculator.calculate(5, 3)); // 출력: 2

calculator.setStrategy(multiplicationStrategy);
console.log(calculator.calculate(5, 3)); // 출력: 15