intro : strategy 패턴에 대해서 알아보자
Strategy 패턴이란 ?
Strategy
패턴은 특정 작업을 수행하는 여러 방식(즉, 전략)을 정의하고, 필요에 따라 이를 교체
하며 사용할 수 있도록 설계된 행동 패턴
입니다. 쉽게 말해, 어떤 작업을 처리하는 방식
(모드)을 각각의 클래스로 분리하고, 실행 시점에 적절한 전략을 선택
해 사용하는 것입니다. 예를 들어, 다이소에서 물건을 결제할 때 다양한 결제 방식을 선택할 수 있는 화면이 나온다고 가정해 보겠습니다. 사용할 수 있는 결제 방식으로는 카드 결제, 현금 결제, 카카오페이 결제, 애플페이 결제, 네이버페이 결제 등이 있을 수 있습니다. 만약 이러한 결제 프로그램을 우리가 작성할 때, 결제라는 행위는 동일
하지만, 선택된 결제 방식에 따라 수행되어야 하는 로직이 달라
지게 됩니다. 이처럼 다양한 결제 방식을 유연하게 처리하기 위해 Strategy 패턴을 적용할 수 있습니다. Strategy 패턴을 통해 각 결제 방식을 별도 클래스로 분리
하고, 실행 시점에 적절한 전략을 선택하여 사용함으로써 코드의 확장성
과 유연성
을 높일 수 있습니다.
Strategy 패턴은 언제 사용하는가 ?
Strategy 패턴은 행동(Behavior)을 캡슐화하고, 다양한 알고리즘(전략)을 동적으로 교체할 수 있도록 설계할 때 사용한다. 이 패턴은 특정 작업을 수행하는 여러 알고리즘(전략)들이 존재하며, 이들 사이를 유연하게 전환하거나 교체해야 할 때 유용하다.
Strategy 패턴 적용 코드 (1)
결제 전략에 사용할 인터페이스
// 결제 방식에 대한 인터페이스
interface PaymentStrategy {
void pay(int amount);
}
결제 전략 인터페이스를 구현한 실제 전략 클래스 (구현체)
// PaymentStrategy 인터페이스를 구현한 신용카드 결제 방식 클래스 구성
class CreditCardPayment implements PaymentStrategy {
private String name;
private String cardNumber;
public CreditCardPayment(String name, String cardNumber) {
this.name = name;
this.cardNumber = cardNumber;
}
@Override
public void pay(int amount) {
System.out.println(amount + " paid with credit card");
}
}
// PaymentStrategy 인터페이스를 구현한 페이팔 결제 방식 클래스 구성
class PayPalPayment implements PaymentStrategy {
private String email;
public PayPalPayment(String email) {
this.email = email;
}
@Override
public void pay(int amount) {
System.out.println(amount + " paid using PayPal");
}
}
각 전략(신용카드결제, 페이팔결제)
에 맞게 결제 메소드를 호출할수 있는 클래스
// CreditCardPayment, PayPalPayment 클래스를 통해 객체를 생성할 수 있는 ShoppingCart 클래스
// setPaymentStrategy 메소드를 통해 어떤 전략이던지 동적으로 선택할 수 있다.
// 해당 클래스의 checkout 메소드를 통해 각 전략에 맞는 결제 메소드를 실행 할 수 있다.
class ShoppingCart {
private PaymentStrategy paymentStrategy;
public void setPaymentStrategy(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}
클라이언트 코드 에서 ShoppingCart 클래스 setPaymentStrategy 메소드를 통해 신용카드 결제 방식으로 결제, 두번째로는 setPaymentStrategy 메소드를 통해 페이팔 결제방식 으로 전환. 다음과 같은 코드를 통해 각 상황에 맞게 전략을 동적으로 선택 할 수 있음을 알 수 있다.
// Client code
public class Main {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(
new CreditCardPayment(
"John Doe",
"1234567890123456"
)
);
//100 paid with credit card
cart.checkout(100);
cart.setPaymentStrategy(
new PayPalPayment(
"johndoe@example.com"
)
);
// 200 paid using PayPal
cart.checkout(200);
}
}
Strategy 패턴 적용 코드 (2)
문자열을 압축하는 프로그램을 구성할건데, 압축하는 방식을 두가지 전략으로 구성하고자 한다. 1번은 각 문자가 연속되는 횟수를 기록하여 문자열을 압축하는 방식, 2번은 문자열의 각 모음을 정해진 숫자로 변환하는 방식이 있다. 해당 상황을 가정하고 아래와 같은 코드를 따라가보자.
압축 전략에 사용할 인터페이스
interface CompressionStrategy {
String compress(String data);
}
압축 전략 인터페이스를 구현한 실제 전략 클래스 (구현체)
class RunLengthEncoding implements CompressionStrategy {
@Override
public String compress(String data) {
StringBuilder compressed = new StringBuilder();
int count = 1;
for (int i = 1; i <= data.length(); i++) {
if (i < data.length() && data.charAt(i) == data.charAt(i - 1)) {
count++;
} else {
compressed.append(data.charAt(i - 1));
compressed.append(count);
count = 1;
}
}
return compressed.toString();
}
}
class SimpleReplacementCompression implements CompressionStrategy {
@Override
public String compress(String data) {
return data.replace("a", "1")
.replace("e", "2")
.replace("i", "3")
.replace("o", "4")
.replace("u", "5");
}
}
각 전략(RunLengthEncoding
, SimpleReplacementCompression
) 에 맞게 압축 메소드를 호출할 수 있는 클래스
// Context class
class Compressor {
private CompressionStrategy strategy;
public void setCompressionStrategy(CompressionStrategy strategy) {
this.strategy = strategy;
}
public String compress(String data) {
return strategy.compress(data);
}
}
클라이언트 코드 에서 Compressor 클래스 setCompressionStrategy
메소드를 통해 RunLengthEncoding
방식으로 압축, 두번째로는 setCompressionStrategy
메소드를 통해 SimpleReplacementCompression
방식으로 전환. 결국 1번에서 확인했던 전략 패턴의 큰 틀의 구조와 같다고 볼 수 있다. 전략패턴을 적용할 상황만 살짝 다를 뿐이었다.
// Client code
public class Main {
public static void main(String[] args) {
Compressor compressor = new Compressor();
String data = "aabcccccaaa";
compressor.setCompressionStrategy(new RunLengthEncoding());
System.out.println(
"RLE Compression: " + compressor.compress(data)
);
// RLE Compression: a2b1c5a3
compressor.setCompressionStrategy(new SimpleReplacementCompression());
System.out.println(
"Simple Replacement: " + compressor.compress(data)
);
// Simple Replacement: 11bccccc111
}
}
Strategy 패턴 요약
Strategy
패턴은 동일한 작업을 수행하는 여러 방법을 정의
하고, 실행 시 적합한 방법을 동적으로 선택
하여 사용하는 행동
패턴이다.