본문 바로가기

개발

변하는 알고리즘을 분리하는 디자인 패턴: 전략 패턴

반응형

최근에 Spring AOP에대해 공부하면서 Spring에서 Bean 주입을 다루거나, 조건에 따라 다른 구현체를 선택해 사용하는 상황을 자주 마주치면서, 그동안 이름만 알고 있던 전략(Strategy) 패턴의 필요성과 구조가 조금씩 체감되기 시작했습니다.

예를 들어 특정 상황 등(예: 결제 방식, 필터 조건, 정렬 알고리즘 등)이 상황에 따라 달라져야 할 때,
하드코딩된 조건문(if-else)을 제거하고, 유연하게 알고리즘을 교체할 수 있는 구조가 필요했습니다.

다양한 문제 상황에서 유용하게 사용할 수 있는 전략 패턴(Strategy Pattern)의 구조와 사용 시점,
그리고 간단한 예제를 통해 그 개념을 정리해보려고 합니다.

 


 

 

전략패턴 ( Strategy Pattern )

컴퓨터 프로그래밍에서 전략 패턴(정책 패턴 이라고도 함) 은 런타임에 알고리즘을 선택할 수 있도록 하는 행동 소프트웨어 설계 패턴 입니다. 단일 알고리즘을 직접 구현하는 대신, 코드는 여러 알고리즘 중 어떤 알고리즘을 사용할지에 대한 런타임 명령을 받습니다.

(feat. 위키 백과)

 

 

전략 패턴의 구조

 

 

전략 패턴(Strategy Pattern)은 행동(알고리즘)을 캡슐화해서, 런타임에 알고리즘을 선택하거나 교체할 수 있도록 도와주는 디자인 패턴입니다. 즉, 여러 개의 유사한 알고리즘이 존재할 때, 그것들을 클래스로 분리하고, 필요에 따라 쉽게 교체할 수 있도록 하는 구조입니다.

✅ 주요 구성 요소

전략 패턴은 보통 다음과 같은 3가지 요소로 구성됩니다:

  1. Strategy (전략 인터페이스)
    • 공통 알고리즘의 인터페이스를 정의합니다.
    • 예: DiscountPolicy, SortingStrategy, PaymentStrategy 등
  2. Concrete (구체적인 구현체)
    • 인터페이스를 구현한 다양한 알고리즘 클래스입니다.
    • 예: FixedDiscountPolicy, PercentageDiscountPolicy
  3. Context (전략을 사용하는 클래스)
    • Strategy 인터페이스에 의존하며, 클라이언트 코드와 전략 구현을 분리합니다.
    • 전략을 실행하는 데 필요한 데이터와 흐름을 제어합니다

 

 

전략 패턴 예제 코드 : 할인 전략

이번 예제에서는 결제 금액에 다양한 할인 정책을 적용하는 상황을 전략 패턴을 통해 구현해보았습니다.

전략 패턴의 핵심은 알고리즘(전략)을 객체로 분리하여, 유연하게 바꿔 끼울 수 있도록 하는 것입니다.

 

// 할인 정책 - 인터페이스
public interface DiscountStrategy {
    int applyDiscount(int price);
}

DiscountStrategy

  • 모든 할인 정책이 따라야 할 공통된 메서드 형태를 정의합니다.
  • applyDiscount라는 메서드는 할인된 가격을 반환하는 책임을 가집니다.
  • 이 인터페이스를 기반으로 다양한 할인 전략들을 구현할 수 있습니다.

 

// 고정 할인 - 구현체
public class FixedDiscountStrategy implements DiscountStrategy {
    @Override
    public int applyDiscount(int price) {
        return price - 1000;
    }
}

// 퍼센트 할인 - 구현체
public class PercentDiscountStrategy implements DiscountStrategy {
    @Override
    public int applyDiscount(int price) {
        return (int)(price * 0.9); // 10% 할인
    }
}

FixedDiscountStrategy

  • 항상 1000원을 고정적으로 할인해주는 전략입니다.
  • 단순한 정액 할인 정책이 필요한 경우에 사용할 수 있습니다.
  • DiscountStrategy 인터페이스를 구현하여, 전략 객체로 사용할 수 있습니다.

PercentDiscountStrategy

  • 총 금액의 10%를 할인해주는 전략입니다.
  • 할인율이 변동되거나, 금액에 따라 할인 폭이 달라지는 경우에 유용합니다.
  • 역시 DiscountStrategy를 구현하고 있어, 쉽게 교체 가능한 전략 객체입니다.

 

// 할인 정책을 사용하는 결제 서비스 - Context
public class PaymentService {
    public void pay(DiscountStrategy strategy, int price) {
        int discounted = strategy.applyDiscount(price);
        System.out.println("기존 금액 : " + price + " | 최종 금액 : " + discounted);
    }
}

 

PaymentService

  • 이 클래스는 전략 객체를 받아서 사용하는 주체(Context)입니다.
  • 어떤 할인 정책을 쓸지는 DiscountStrategy 구현체에 따라 달라지며, PaymentService는 그 내부 동작을 몰라도 됩니다.
  • pay 메서드는 주어진 가격에 할인 전략을 적용한 결과를 출력합니다.
  • 이처럼 전략을 외부에서 주입받기 때문에, 전략 변경이 자유롭고, OCP(개방-폐쇄 원칙)도 잘 지켜집니다.

 

// 할인 전략 설정
PaymentService paymentService = new PaymentService();

// 고정 할인 전략 실행
paymentService.pay(new FixedDiscountStrategy(), 20000); 
// LOG : 기존 금액 : 20000 | 최종 금액 : 19000

// 퍼센트 할인 전략 실행
paymentService.pay(new PercentDiscountStrategy(), 20000); 
// LOG : 기존 금액 : 20000 | 최종 금액 : 18000
  • PaymentService 객체는 Context 역할로, 구체적인 할인 전략을 직접 결정하지 않고 외부에서 주입받습니다.
  • FixedDiscountStrategy는 1,000원을 고정으로 할인하는 전략이고,
    PercentDiscountStrategy는 10%를 할인하는 전략입니다.
  • 같은 금액(20,000원)에 대해 두 가지 전략을 적용해 유연하게 할인 로직을 변경할 수 있음을 보여줍니다.

 

 

전략 패턴의 특징, 장단점

 

🌟 장점

  • OCP(개방-폐쇄 원칙) 준수
    새로운 전략을 추가해도 기존 코드를 수정하지 않아도 되기 때문에, 변경에 강하고 유지보수에 유리
  • 코드 중복 제거 및 역할 분리
    다양한 알고리즘(전략)을 별도의 클래스로 분리함으로써, 각 클래스가 하나의 책임만 갖도록 구성
  • 동적으로 전략 변경 가능
    실행 시점에 전략을 바꿔서 유연하게 동작을 변경 -> 런타임에 전략을 설정하거나 교체해야 하는 상황에 매우 유용

 

 

⚠️ 단점

  • 클래스 수 증가
    전략마다 별도의 클래스를 만들어야 하므로, 간단한 로직에까지 적용할 경우 오히려 구조가 복잡해짐
  • 전략 간 인터페이스 강제
    전략이 모두 동일한 인터페이스를 구현해야 하므로, 너무 이질적인 전략끼리는 억지로 맞춰야 할 수도 있음
  • 클라이언트 코드가 전략 선택 책임을 가짐
    어떤 전략을 사용할지는 클라이언트에서 직접 결정해야 하므로, 외부에서 전략 선택 로직관리 필요

 

 

📌 정리

이번 글에서는 전략 패턴(Strategy Pattern)의 구조와 특징, 그리고 실생활 예제인 할인 정책 로직을 통해 구체적으로 살펴보았습니다.
전략 패턴은 유연하고 확장 가능한 설계를 가능하게 해주며, 변화가 잦은 비즈니스 로직을 다룰 때 매우 유용하게 사용될 수 있습니다.

다만, 모든 상황에 무조건 적용하는 것이 아니라, 복잡도가 올라가는 상황에서 책임을 명확히 나누고, 전략을 캡슐화하고 싶을 때 선택하면 좋은 패턴입니다.

앞으로도 실무에서 마주치는 반복되는 구조나 조건문들이 보인다면, 그 흐름 속에서 전략 패턴을 떠올려 보는 것도 좋아 보인다.

반응형