도찐개찐
[코드디자인패턴-JAVA] Strategy Pattern 본문
Strategy Pattern
사용시점
- 여러 알고리즘 중 선택 가능할 때: 같은 문제를 해결하는 데 여러 가지 방법이 있을때, 알고리즘을 쉽게 변경하거나 확장하고자 할 때 사용 합니다.
- 알고리즘 변경이 클라이언트 고트에 영향을 미치지 않아야 할 때: 전략 패턴을 사용하면 알고리즘을 변경해도 클라이언트 코드를 변경할 필요가 없게 됩니다.
- 클래스의 행위를 동적으로 변경하고 싶을 때: 실행 중에 동적으로 특정 행위를 변경하고자 할 때 사용할 수 있습니다.
종류
Strategy Pattern 자체는 특정한 "종류"가 있는 것이 아니라, 알고리즘의 행동을 인터페이스로 정의하고, 이를 구현하는 여러 전략 클래스를 제공하는 구조입니다.
- 정렬 알고리즘을 캡슐화한 전략(버블 정렬, 퀵 정렬, 병합 정렬 등)
- 할인 정책을 캡슐화한 전략(고객 등급별 할인, 특별 이벤트 할인 등)
- 인증 방식을 캡슐화한 전략(OAuth 인증, 토큰 인증 등)
특징
- 특정 컨텍스트에 따라 적합한 전략을 선택, 실행
- 코드의 유연성과 재사용성을 향상
- 특정 작업을 수행하는 알고리즘이나 행위를 캡슐화
- 작업을 수행하는 전략을 쉽게 교체할 수 있도록 하는 디자인 패턴
// 전략 인터페이스
public interface PaymentStrategy {
void pay(int amount);
}
// 신용카드를 사용하는 전략
public class CreditCardStrategy implements PaymentStrategy {
private String cardNumber;
private String name;
public CreditCardStrategy(String cardNumber, String name) {
this.cardNumber = cardNumber;
this.name = name;
}
[Strategy Pattern.html](Strategy%20Pattern.html)
@Override
public void pay(int amount) {
System.out.println("신용 카드로 " + amount + "원을 지불 했습니다.");
}
}
// PayPal을 사용하는 전략
public class PaypalStrategy implements PaymentStrategy {
private String email;
public PaypalStrategy(String email) {
this.email = email;
}
@Override
public void pay(int amount) {
System.out.println("PayPal로 " + amount + "원을 지불 했습니다.");
}
}
// 결제 컨텍스트
public class ShoppingCart {
private PaymentStrategy paymentStrategy;
public ShoppingCart(PaymentStrategy paymentStrategy) {
this.paymentStrategy = paymentStrategy;
}
public void checkout(int amount) {
paymentStrategy.pay(amount);
}
}
public class Main {
public static void main(String[] args) {
ShoppingCart cart1 = new ShoppingCart(new CreditCardStrategy("1234-5678-1234-5678", "홍길동"));
cart1.checkout(5000);
ShoppingCart cart2 = new ShoppingCart(new PaypalStrategy("dev-truly@example.com"));
cart2.checkout(31000);
}
}
Main.main(null)
신용 카드로 5000원을 지불 했습니다.
PayPal로 31000원을 지불 했습니다.
위의 예시에서 PaymentStrategy 인터페이스는 다양한 결제 전략을 정의하고,
CreditCardStrategy와 PaypalStrategy 클래스는 이 인터페이스를 구현합니다.
ShoppingCart 클래스는 결제 방식을 추상화하고, 전략을 변경하거나 확장하기 쉽게 만들어 줍니다.
Stragegy Pattern 사용 대표 자바 라이브러리
Comparator
인터페이스는 객체를 비교하는 다양한 전략을 정의 하는 데 사용 될 수 있으며,
이는 Collections.sort
와 같은 정렬 메서드에서 사용 될 수 있습니다.
import java.util.Arrays;
import java.util.Comparator;
public class StrategyExample {
public static void main(String[] args) {
Integer[] numbers = { 3, 1, 4, 1, 5, 9, 2, 6 };
// 익명 클래스를 사용한 전략
Arrays.sort(numbers, new Comparator<Integer>() {
public int compare(Integer a, Integer b) {
return a - b; // 오름차순 정렬
}
});
for (int number : numbers) System.out.print(number + " ");
System.out.println("");
// 람다를 사용한 전략 (Java 8 이상)
Arrays.sort(numbers, (a, b) -> b - a); // 내림차순 정렬
for (int number : numbers) System.out.print(number + " ");
}
}
StrategyExample.main(null)
1 1 2 3 4 5 6 9
9 6 5 4 3 2 1 1
장점
- 유연성: 전략 패턴을 사용하면 알고리즘을 쉽게 변경하거나 확장 할 수 있습니다. 새로운 전략을 추가 하려면 기존 코드를 변경할 필요가 없으므로 유지보수가 쉽습니다.
- 재사용성: 전략 객체는 여러 컨텍스트에서 재사용 될 수 있습니다. 동일한 알고리즘이 여러곳에서 필요한 경우 전략 패턴을 사용하면 코드 중복을 피할 수 있습니다.
- 의존성분리: 알고리즘과 그것을 사용하는 클라이언트 코드 간의 결합도를 낮춥니다. 이로 인해 시스템의 각 부분이 독립적으로 변경하고 테스트 할 수 있게 됩니다.
단점
- 복잡도 증가: 전략 패턴을 사용하면 여러 전략 클래스와 컨텍스트 클래스가 추가 될 수 있으므로, 설계가 복잡해 질 수 있습니다. 필요 이상으로 사용 될 경우 이해하고 유지 보수하기 어려울 수 있습니다.
- 런타임 오버헤드: 전략 패턴은 객체 지향적인 접근 방식이므로 런타임에 추가 메모리와 프로세싱 오버헤드가 발생 할 수 있습니다. 성능이 매우 중요한 경우에는 이 패턴의 사용이 제한 될 수 있습니다.
결론
- 알고리즘의 변경과 확장, 재사용성 향상, 결함도 감소 이점
- 설계의 복잡성, 런타임 오버헤드 등을 고려 필요
728x90
'프로그래밍 > 코드디자인패턴' 카테고리의 다른 글
[코드디자인패턴-JAVA] Facade Pattern (0) | 2024.02.29 |
---|---|
[코드디자인패턴-JAVA] Factory Method Pattern (0) | 2024.02.29 |
[코드디자인패턴-JAVA] Observer Pattern (0) | 2024.02.29 |
[코드디자인패턴-JAVA] Singleton Pattern (0) | 2024.02.29 |
[코드디자인패턴-JAVA] State Pattern (0) | 2024.02.29 |
Comments