전략 패턴
Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 104개 중 95번째.
Strategy 패턴은 알고리즘군을 정의하고, 각 알고리즘을 캡슐화하며, 서로 바꿔 사용할 수 있도록 합니다. 이를 통해 객체의 코드를 수정하지 않고 런타임에 객체의 동작을 변경할 수 있습니다. 즉, 알고리즘은 이를 사용하는 클라이언트와 독립적으로 변경됩니다.
이 패턴은 세 부분으로 구성됩니다. 알고리즘 Method을 선언하는 Strategy interface, 서로 다른 변형을 구현하는 Concrete Strategies, 그리고 전략을 사용하는 Context입니다.
#include <iostream>
#include <memory>
// 전략 인터페이스
class PaymentStrategy {
public:
virtual void pay(int amount) = 0;
virtual ~PaymentStrategy() = default;
};
// 구체적인 전략
class CreditCardPayment : public PaymentStrategy {
public:
void pay(int amount) override {
std::cout << "Paid " << amount << " via Credit Card\n";
}
};
class PayPalPayment : public PaymentStrategy {
public:
void pay(int amount) override {
std::cout << "Paid " << amount << " via PayPal\n";
}
};
// 컨텍스트
class ShoppingCart {
std::unique_ptr<PaymentStrategy> strategy;
public:
void setPaymentMethod(std::unique_ptr<PaymentStrategy> s) {
strategy = std::move(s);
}
void checkout(int total) {
if (strategy) strategy->pay(total);
}
};
int main() {
ShoppingCart cart;
cart.setPaymentMethod(std::make_unique<CreditCardPayment>());
cart.checkout(100);
cart.setPaymentMethod(std::make_unique<PayPalPayment>());
cart.checkout(50);
}ShoppingCart은 어떤 결제 방법을 사용하는지 알지 못합니다. 단지 설정된 전략에서 pay()를 호출할 뿐입니다. setPaymentMethod()를 사용하면 런타임에 전략을 교체할 수 있으므로, 시스템이 유연해지고 새로운 결제 옵션으로 쉽게 확장할 수 있습니다.
특정 작업에 사용할 여러 알고리즘이 있고 이를 동적으로 전환하려는 경우, 또는 동작을 선택하기 위한 조건문을 피하려는 경우 Strategy를 사용하세요.
챌린지
쉬움Strategy 패턴을 사용하여 다양한 배송 방법을 기반으로 배송 비용을 계산하는 배송 계산기를 만들어 보겠습니다. 이는 런타임에 알고리즘을 교체해야 하는 실용적인 시나리오입니다. 동일한 패키지를 ground, air 또는 express 방식으로 배송할 수 있으며, 각 방식에는 고유한 가격 책정 로직이 있습니다.
코드를 세 개의 파일로 구성합니다:
ShippingStrategy.h: strategy interface와 구체적인 배송 전략을 define합니다.ShippingStrategyabstract class를 만들고, 배송 비용을 double로 반환하는 pure virtual methodcalculateCost(double weight)와 virtual destructor를 포함합니다.그런 다음 세 가지 구체적인 전략을 Implement합니다:
GroundShipping: weight 단위당1.5의 비용 (weight * 1.5)AirShipping: weight 단위당4.0의 비용 (weight * 4.0)ExpressShipping: weight 단위당6.5의 비용에 고정 요금10.0을 더함 (weight * 6.5 + 10.0)
ShippingService.h: shipping strategy를 사용하는 Context class를 만듭니다.ShippingServiceclass는std::unique_ptr<ShippingStrategy>를 private member로 보유해야 합니다. 다음을 Implement합니다:- shipping method를 변경하는
setStrategy(std::unique_ptr<ShippingStrategy> strategy)method - current strategy를 사용하여 비용을 계산하고 반환하는
calculateShipping(double weight)method
calculateShipping이 호출될 때 strategy가 설정되어 있지 않다면0.0을 return합니다.- shipping method를 변경하는
main.cpp: 런타임에 strategy를 전환하는 과정을 보여 줍니다.두 개의 input을 읽습니다:
- 패키지 weight (double)
- shipping method:
ground,air또는express
ShippingService를 생성하고 input method를 기반으로 appropriate strategy를 설정합니다. 배송 비용을 계산하고 출력합니다.그런 다음 다른 strategy로 전환합니다 (input이
air가 아니면air를 사용하고, 그렇지 않으면ground를 사용합니다). 그리고 동일한 weight에 대해 비용을 다시 계산합니다. 이는 런타임에 strategy를 교체하는 것의 장점을 보여 줍니다.각 비용을 정확히 소수점 한 자리로, method name을 앞에 붙여 한 줄에 하나씩 출력합니다:
[Method]: $[cost]
예를 들어 input이 5.0과 ground인 경우:
Ground: $7.5
Air: $20.0input이 3.0과 express인 경우:
Express: $29.5
Air: $12.0input이 10.0과 air인 경우:
Air: $40.0
Ground: $15.0ShippingService는 각 가격 책정 알고리즘의 세부 사항을 알 필요가 없다는 점에 주목하세요. 현재 설정된 strategy에 단순히 위임할 뿐입니다. service class를 전혀 수정하지 않고도 새로운 shipping method(예: drone delivery 또는 당일 배송)를 쉽게 추가할 수 있습니다.
직접 해보기
#include <iostream>
#include <string>
#include <iomanip>
#include <memory>
#include "ShippingStrategy.h"
#include "ShippingService.h"
int main() {
double weight;
std::string method;
std::cin >> weight;
std::cin >> method;
// 출력을 소수점 1자리로 설정
std::cout << std::fixed << std::setprecision(1);
ShippingService service;
// TODO: 입력 방법("ground", "air", 또는 "express")에 따라:
// 1. 서비스에 적절한 전략을 설정
// 2. 다음 형식으로 비용을 계산하고 출력: "[Method]: $[cost]"
// TODO: 다른 전략으로 전환:
// - 입력이 "air"였다면 GroundShipping으로 전환
// - 그렇지 않으면 AirShipping으로 전환
// 새 비용을 계산하고 출력
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 C++ 컴파일러