Design Pattern

Strategy Pattern

창욱씨 2024. 1. 10. 21:35
반응형

Strategy Pattern (전략 패턴)

개념

Strategy Pattern은 행위(Behavioral) 디자인 패턴 중 하나로, 알고리즘군을 정의하고 각각을 캡슐화하여 교환 가능하게 만드는 패턴입니다. 클라이언트 코드를 변경하지 않고도 런타임에 알고리즘을 자유롭게 교체할 수 있습니다.

핵심 원칙

"변하는 것을 캡슐화하라" — 변경되는 부분(알고리즘)을 인터페이스 뒤에 숨기고, 변경되지 않는 부분(컨텍스트)과 분리한다.

구조

classDiagram
    class Context {
        -strategy: Strategy
        +setStrategy(Strategy)
        +executeStrategy()
    }

    class Strategy {
        <<interface>>
        +execute()
    }

    class ConcreteStrategyA {
        +execute()
    }

    class ConcreteStrategyB {
        +execute()
    }

    class ConcreteStrategyC {
        +execute()
    }

    Context --> Strategy
    Strategy <|.. ConcreteStrategyA
    Strategy <|.. ConcreteStrategyB
    Strategy <|.. ConcreteStrategyC
구성 요소 역할
Strategy (인터페이스) 알고리즘의 공통 인터페이스 정의
ConcreteStrategy 실제 알고리즘 구현체
Context Strategy 객체를 보유하고, 클라이언트에게 알고리즘 실행을 위임

예시: 결제 시스템

// 1. Strategy 인터페이스
public interface PaymentStrategy {
    void pay(int amount);
}

// 2. 구체적인 전략들
public class CreditCardPayment implements PaymentStrategy {
    private String cardNumber;

    public CreditCardPayment(String cardNumber) {
        this.cardNumber = cardNumber;
    }

    @Override
    public void pay(int amount) {
        System.out.println(amount + "원을 신용카드로 결제합니다.");
    }
}

public class KakaoPayPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println(amount + "원을 카카오페이로 결제합니다.");
    }
}

public class NaverPayPayment implements PaymentStrategy {
    @Override
    public void pay(int amount) {
        System.out.println(amount + "원을 네이버페이로 결제합니다.");
    }
}

// 3. Context
public class ShoppingCart {
    private PaymentStrategy paymentStrategy;

    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;
    }

    public void checkout(int amount) {
        paymentStrategy.pay(amount);
    }
}

// 4. 클라이언트 코드
public class Main {
    public static void main(String[] args) {
        ShoppingCart cart = new ShoppingCart();

        // 런타임에 전략 교체 가능!
        cart.setPaymentStrategy(new CreditCardPayment("1234-5678"));
        cart.checkout(50000);

        cart.setPaymentStrategy(new KakaoPayPayment());
        cart.checkout(30000);
    }
}

Strategy Pattern을 안 쓰면?

// ❌ if-else 지옥 — OCP(개방-폐쇄 원칙) 위반
public void pay(String type, int amount) {
    if (type.equals("credit")) {
        // 신용카드 결제 로직
    } else if (type.equals("kakao")) {
        // 카카오페이 결제 로직
    } else if (type.equals("naver")) {
        // 네이버페이 결제 로직
    }
    // 새 결제 수단 추가 시 이 메서드를 계속 수정해야 함!
}

장점과 단점

장점 단점
✅ OCP 준수 — 새 전략 추가 시 기존 코드 수정 불필요 ❌ 전략이 적으면 오버엔지니어링이 될 수 있음
✅ 런타임 교체 — 실행 중 알고리즘 변경 가능 ❌ 클라이언트가 구체적인 전략의 차이를 알아야 함
✅ 조건문 제거 — if/else, switch 분기 제거 ❌ 전략 클래스 수가 증가할 수 있음
✅ 테스트 용이 — 각 전략을 독립적으로 테스트 가능  

실무에서의 활용 사례

  • 정렬 알고리즘 교체 — Collections.sort(list, comparator)에서 Comparator가 Strategy
  • 인증 방식 — JWT, OAuth, Session 등 인증 전략 교체
  • 파일 압축 — ZIP, GZIP, LZ4 등 압축 알고리즘 선택
  • 로깅 — Console, File, DB 등 로깅 대상 전환
  • 할인 정책 — 정액 할인, 정률 할인, 쿠폰 할인 등

관련 패턴과의 차이

패턴 차이점
Template Method 상속 기반으로 알고리즘 골격을 정의. Strategy는 위임(composition) 기반
State 구조는 유사하나, State는 상태 전이에 초점. Strategy는 알고리즘 교체에 초점
Factory 객체 생성에 관한 패턴. Strategy는 객체의 행위에 관한 패턴
반응형