전략 패턴
Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 87개 중 69번째.
전략 패턴(Strategy Pattern)은 일련의 알고리즘을 정의하고, 각 알고리즘을 개별 클래스에 캡슐화하여 이들을 서로 교체할 수 있도록 만드는 행동 디자인 패턴입니다. 특정 동작을 직접 하드코딩하는 대신, 이를 사용하는 코드를 변경하지 않고도 런타임에 알고리즘을 교체할 수 있습니다.
여러 결제 수단을 지원하는 결제 시스템을 상상해 보세요. 전략 패턴(Strategy Pattern)이 없다면, 복잡한 조건부 로직이 만들어질 것입니다. 전략 패턴을 사용하면, 각 결제 수단은 고유한 전략이 됩니다:
interface PaymentStrategy {
void pay(int amount);
}
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal");
}
}context 클래스는 전략에 대한 참조를 유지하고 작업을 해당 전략에 위임합니다. 핵심은 context가 어떤 구체적인 전략을 사용하고 있는지 알지 못하며, 오직 인터페이스만 알고 있다는 점입니다:
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}이제 결제 동작을 동적으로 변경할 수 있습니다:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // 신용카드로 100 결제됨
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // PayPal로 50 결제됨전략 패턴(Strategy Pattern)은 하나의 동작을 수행하는 여러 가지 방법이 있고, 이들 사이를 쉽게 전환하고 싶을 때 빛을 발합니다. 새로운 결제 수단을 추가하는 것은 단순히 PaymentStrategy를 구현하는 새로운 클래스를 생성하는 것을 의미하며, 기존 코드를 변경할 필요가 없습니다.
챌린지
쉬움전략 패턴(Strategy Pattern)을 사용하여 텍스트 포맷팅 시스템을 구축해 봅시다! 런타임에 다양한 포맷팅 전략을 교체하여 텍스트를 여러 방식으로 변환할 수 있는 시스템을 만들게 됩니다. 이는 여러 출력 형식을 지원해야 하는 애플리케이션에 적합합니다.
코드는 다음 네 개의 파일로 구성됩니다:
TextFormatter.java: 모든 포맷팅 전략이 구현할TextFormatter인터페이스를 정의합니다. 문자열을 받아 포맷팅된 버전을 반환하는 단일 메서드String format(String text)를 선언해야 합니다.Formatters.java:TextFormatter인터페이스를 구현하는 세 가지 구체적인 전략을 생성합니다:UpperCaseFormatter- 텍스트를 모두 대문자로 변환합니다.LowerCaseFormatter- 텍스트를 모두 소문자로 변환합니다.TitleCaseFormatter- 각 단어의 첫 글자는 대문자로, 나머지는 소문자로 변환합니다. 단어는 공백으로 구분됩니다.TextEditor.java: 포맷팅 전략을 사용하는 컨텍스트 클래스를 생성합니다.TextEditor는 다음을 포함해야 합니다:현재
TextFormatter전략을 저장할 private 필드.활성 포맷팅 전략을 변경하는
setFormatter(TextFormatter formatter)메서드.현재 포맷터를 텍스트에 적용하고
Published: [formatted text]를 출력하는publishText(String text)메서드. 만약 포맷터가 설정되지 않았다면, 변경되지 않은Published: [original text]를 출력해야 합니다.Main.java: 전략 시스템을 하나로 묶습니다! 포맷할 텍스트(String)와 포맷팅 스타일(String:"upper","lower", 또는"title")의 두 가지 입력을 받습니다.TextEditor를 생성하고, 포맷터를 설정하기 전에 입력 텍스트로publishText를 먼저 호출합니다(기본 동작 확인).그런 다음, 입력된 스타일에 따라 적절한 포맷터 전략을 설정하고 동일한 텍스트로
publishText를 다시 호출하여 포맷팅된 결과를 보여줍니다.
포맷할 텍스트(String)와 포맷팅 스타일(String)의 두 가지 입력을 순서대로 받게 됩니다.
예를 들어, 입력이 hello world와 title인 경우, 출력은 다음과 같습니다:
Published: hello world
Published: Hello WorldTextEditor가 구체적인 포맷팅 로직에 대해 전혀 알지 못한다는 점에 주목하세요. 단순히 현재 설정된 전략에 위임할 뿐입니다. 덕분에 에디터 코드를 수정하지 않고도 새로운 포맷팅 스타일을 아주 쉽게 추가할 수 있습니다!
치트 시트
전략 패턴(Strategy Pattern)은 알고리즘군을 정의하고 각각을 별도의 클래스에 캡슐화하여 이들을 상호 교환 가능하게 만드는 행동 디자인 패턴입니다. 이를 통해 알고리즘을 사용하는 코드를 변경하지 않고도 런타임에 알고리즘을 교체할 수 있습니다.
주요 구성 요소
전략 인터페이스(Strategy Interface): 모든 구체적인 전략들을 위한 공통 인터페이스를 정의합니다.
interface PaymentStrategy {
void pay(int amount);
}구체적인 전략(Concrete Strategies): 특정 알고리즘을 사용하여 전략 인터페이스를 구현합니다.
class CreditCardPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
public void pay(int amount) {
System.out.println("Paid " + amount + " via PayPal");
}
}컨텍스트 클래스(Context Class): 전략에 대한 참조를 유지하고 작업을 해당 전략에 위임합니다. 컨텍스트는 구체적인 구현이 아닌 인터페이스만 알고 있습니다.
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}사용법
전략은 런타임에 동적으로 변경될 수 있습니다:
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100); // Paid 100 via Credit Card
cart.setPaymentStrategy(new PayPalPayment());
cart.checkout(50); // Paid 50 via PayPal장점
전략 패턴은 하나의 동작을 수행하는 여러 방법이 있고 이들 사이를 쉽게 전환하고 싶을 때 이상적입니다. 새로운 전략을 추가하는 것은 단순히 전략 인터페이스를 구현하는 새로운 클래스를 생성하는 것을 의미하며, 기존 코드를 변경할 필요가 없습니다.
직접 해보기
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String text = scanner.nextLine();
String style = scanner.nextLine();
// TODO: TextEditor 인스턴스 생성
// TODO: 입력 텍스트를 사용하여 publishText 호출 (포매터를 설정하기 전)
// TODO: style 입력("upper", "lower", 또는 "title")에 따라,
// 적절한 포매터를 설정하고 publishText를 다시 호출
}
}이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
4상속
상속의 기초 (extends)super 키워드메서드 오버라이딩 (@Override)생성자 체이닝Object 클래스단일 및 다중 레벨 상속다중 클래스 상속이 불가능한 이유요약 - 직원 계층 구조