Menu
Coddy logo textTech

전략 패턴

Coddy Dart 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 110개 중 93번째.

전략 패턴(Strategy pattern)은 일련의 알고리즘을 정의하고, 각 알고리즘을 개별 클래스에 캡슐화하여 실행 시점에 이들을 서로 교체해서 사용할 수 있게 합니다. 클래스 내부에 동작을 직접 하드코딩하는 대신 인터페이스를 통해 동작을 주입함으로써, 해당 동작을 사용하는 클래스를 수정하지 않고도 전략을 자유롭게 바꿀 수 있습니다.

다양한 결제 수단을 지원하려는 결제 시스템을 고려해 보세요. 각 수단을 처리하기 위해 조건문을 사용하는 대신, 전략 인터페이스를 정의하고 구체적인 구현체를 만듭니다:

abstract class PaymentStrategy {
  void pay(double amount);
}

class CreditCardPayment implements PaymentStrategy {
  @override
  void pay(double amount) => print('Paid \$amount with Credit Card');
}

class PayPalPayment implements PaymentStrategy {
  @override
  void pay(double amount) => print('Paid \$amount with PayPal');
}

class ShoppingCart {
  PaymentStrategy _paymentStrategy;

  ShoppingCart(this._paymentStrategy);

  void setPaymentStrategy(PaymentStrategy strategy) {
    _paymentStrategy = strategy;
  }

  void checkout(double total) {
    _paymentStrategy.pay(total);
  }
}

void main() {
  var cart = ShoppingCart(CreditCardPayment());
  cart.checkout(99.99);  // Credit Card로 $99.99 결제됨

  cart.setPaymentStrategy(PayPalPayment());
  cart.checkout(49.99);  // PayPal로 $49.99 결제됨
}

ShoppingCart는 결제가 어떻게 작동하는지 알거나 신경 쓰지 않습니다. 단지 현재 설정된 전략(strategy)에 위임할 뿐입니다. 장바구니 코드를 건드리지 않고도 새로운 전략 클래스를 생성하여 새로운 결제 수단을 추가할 수 있습니다. 이 패턴은 하나의 동작을 수행하는 여러 방법이 있고, 그것들을 동적으로 선택하거나 전환하고 싶을 때 이상적입니다.

challenge icon

챌린지

쉬움

전략(Strategy) 패턴을 사용하여 텍스트 포맷팅 시스템을 구축해 봅시다! 핵심 텍스트 프로세서를 변경하지 않고도 사용자가 동적으로 포맷을 전환할 수 있도록, 텍스트에 다양한 포맷팅 전략을 적용할 수 있는 시스템을 만들 것입니다.

코드는 두 개의 파일로 구성됩니다:

  • formatting_strategies.dart: 여기에 전략 시스템을 만듭니다. String format(String text) 메서드를 가진 추상 클래스 FormattingStrategy를 정의하세요. 그런 다음 세 가지 구체적인 전략을 구현합니다:
    • UppercaseStrategy - 텍스트를 모두 대문자로 변환합니다.
    • LowercaseStrategy - 텍스트를 모두 소문자로 변환합니다.
    • TitleCaseStrategy - 각 단어의 첫 글자를 대문자로 변환합니다 (공백으로 분리하고, 각 단어의 첫 글자는 대문자로, 나머지는 소문자로 변환).
    또한 FormattingStrategy를 보유하는 TextProcessor 클래스를 만듭니다. 이 클래스는 초기 전략을 받아들이는 생성자, 런타임에 전략을 변경하는 setStrategy() 메서드, 그리고 현재 전략을 적용하여 포맷된 결과를 반환하는 process(String text) 메서드를 가져야 합니다.
  • main.dart: 포맷팅 전략을 임포트하고 전략 패턴이 어떻게 동적인 동작 전환을 가능하게 하는지 보여줍니다. UppercaseStrategy로 시작하는 TextProcessor를 생성하세요. hello world 텍스트를 처리하고 결과를 출력합니다. 그런 다음 LowercaseStrategy로 전환하여 HELLO WORLD를 처리하고 출력합니다. 마지막으로 TitleCaseStrategy로 전환하여 the quick brown fox를 처리하고 결과를 출력합니다.

이것은 전략 패턴의 강력함을 보여줍니다. TextProcessor는 포맷팅이 어떻게 작동하는지 세부 사항을 알 필요가 없습니다. 단순히 현재 설정된 전략에 위임할 뿐이므로, 프로세서를 수정하지 않고도 새로운 포맷팅 옵션을 쉽게 추가할 수 있습니다!

예상 출력:

HELLO WORLD
hello world
The Quick Brown Fox

치트 시트

전략 패턴(Strategy pattern)은 일련의 알고리즘을 정의하고, 각 알고리즘을 개별 클래스로 캡슐화하여 런타임에 서로 교체 가능하게 만듭니다. 동작을 직접 코딩하는 대신 인터페이스를 통해 주입합니다.

전략 인터페이스를 정의합니다:

abstract class PaymentStrategy {
  void pay(double amount);
}

구체적인 전략 구현체를 생성합니다:

class CreditCardPayment implements PaymentStrategy {
  @override
  void pay(double amount) => print('Paid \$amount with Credit Card');
}

class PayPalPayment implements PaymentStrategy {
  @override
  void pay(double amount) => print('Paid \$amount with PayPal');
}

전략을 사용하는 컨텍스트 클래스를 생성합니다:

class ShoppingCart {
  PaymentStrategy _paymentStrategy;

  ShoppingCart(this._paymentStrategy);

  void setPaymentStrategy(PaymentStrategy strategy) {
    _paymentStrategy = strategy;
  }

  void checkout(double total) {
    _paymentStrategy.pay(total);
  }
}

전략을 주입하고 교체하여 패턴을 사용합니다:

var cart = ShoppingCart(CreditCardPayment());
cart.checkout(99.99);  // 신용카드로 $99.99 결제됨

cart.setPaymentStrategy(PayPalPayment());
cart.checkout(49.99);  // 페이팔로 $49.99 결제됨

컨텍스트 클래스는 구현 세부 사항을 알지 못한 채 전략에 동작을 위임합니다. 기존 코드를 수정하지 않고 새로운 클래스를 생성하여 새로운 전략을 추가할 수 있습니다.

직접 해보기

import 'formatting_strategies.dart';

void main() {
  // TODO: UppercaseStrategy로 시작하는 TextProcessor 생성
  
  // TODO: 'hello world' 텍스트를 처리하고 결과 출력
  
  // TODO: LowercaseStrategy로 전환
  
  // TODO: 'HELLO WORLD'를 처리하고 결과 출력
  
  // TODO: TitleCaseStrategy로 전환
  
  // TODO: 'the quick brown fox'를 처리하고 결과 출력
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨