전략 패턴(Strategy Pattern)

2025. 3. 18. 15:11·Computer Science/Design Pattern

1. 전략 패턴(Strategy Pattern)

- 정책 패턴(Policy Pattern)이라고도 한다.

- 객체의 행위를 바꾸고 싶은 경우 '직접' 수정하지 않고 '전략'이라고 부르는 '캡슐화한 알고리즘'을 컨텍스트안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴.

- 즉, 어떤 기능을 수행하는 여러 가지 방법(전략)이 있을 때, 실행 시점에서 적절한 전략을 선택하여 사용할 수 있도록 설계하는 패턴.


2. Java의 전략 패턴 예시 코드

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

// 2. 다양한 전략(결제 방법) 구현
class CreditCardPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println(amount + "원 신용카드 결제 완료!");
    }
}

class PayPalPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println(amount + "원 PayPal 결제 완료!");
    }
}

// 3. 결제 컨텍스트(Context) 클래스
class PaymentProcessor {
    private PaymentStrategy strategy;

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

    public void pay(int amount) {
        if (strategy == null) {
            System.out.println("결제 방식이 설정되지 않았습니다.");
            return;
        }
        strategy.pay(amount);
    }
}

// 4. 실행 코드 (Main)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        PaymentProcessor processor = new PaymentProcessor();

        System.out.println("결제 방식을 선택하세요: 1. 신용카드  2. PayPal");
        int choice = scanner.nextInt();

        //if-else 문을 사용하여 사용자가 선택한 결제 방식을 설정
        if (choice == 1) {
            processor.setPaymentStrategy(new CreditCardPayment());
        } else if (choice == 2) {
            processor.setPaymentStrategy(new PayPalPayment());
        } else {
            System.out.println("잘못된 선택입니다.");
            return;
        }

        processor.pay(5000);
    }
}

코드 분석

1. PaymentStrategy 인터페이스

  • 결제 방식을 정의하는 인터페이스

2. CreditCartPayment, PayPalPayment 클래스

  • 결제 방식(전략)을 각각 구현

3. PaymentProcessor 컨텍스트

  • PaymentStrategy를 설정하고 실행하는 역할

4. Main 클래스

  • 사용자가 결제 방식을 선택하고 실행하는 부분

실행 과정

Main 클래스 > 실행 시작

  • Scanner 객체를 생성하여 사용자 입력 받기 준비 완료 !
  • PaymentProcessor 객체를 생성하여 결제 전략을 설정할 준비 완료 !
  • 사용자가 결제 방식을 선택하면 choice 변수에 값 저장
  • if-else 문을 사용하여 전략 설정

3. 전략 패턴의 장단점

장점

*OCP(개방-폐쇄 원칙, Open-Closed Principle): 기능을 확장할 수는 있지만, 기존 코드를 수정하지 않고 확장해야 한다.

  1. 실행 중 알고리즘(전략) 변경 가능 > 유연성 증가: 전략을 인터페이스로 추상화했기 때문에 실행중에 변경 가능하다.
  2. 코드 중복 제거 > 유지보수 용이: 각 알고리즘(전략)을 별도의 클래스로 분리하므로 중복된 코드가 사라진다.
  3. *OCP를 만족: 확장에는 열려 있고, 수정에는 닫혀 있음
  4. 결합도 감소 > 코드 유연성 증가: 클라이언트 코드가 특정 알고리즘(전략)과 강하게 결합되지 않음
  5. 테스트 및 코드 재사용 용이: 각 알고리즘(전략)이 독립적인 클래스로 분리되어 있어 단위 테스트가 쉬움, 공통 인터페이스를 사용하여 전략을 교체할 수 있음.

단점

  1. 클래스 수 증가 > 코드 복잡성 증가: 각 전략을 별도의 클래스로 분리해야 하므로 클래스 수가 증가, 작은 프로젝트에서는 오히려 불필요한 복잡성을 초래함.
  2. 클라이언트가 전략을 명시적으로 설정해야 함: 실수로 전략을 설정하지 않으면 NullPointerException 발생 가능 !!
  3. 전략 선택 로직이 분산될 수 있음: 클라이언트 코드에서 매번 전략을 선택해야 하므로 전략 선택 로직이 분산될 수 있음.

4. 전략 패턴을 사용해야 하는 경우

1. 여러 개의 알고리즘이 필요할 때

- 동일한 작업을 수행하는 여러 개의 알고리즘이 있을 때 사용

- 실행 중에 원하는 알고리즘을 선택하고 적용할 수 있어야 함 !

- ex) 정렬 알고리즘의 선택

2. 런타임에서 전략을 변경해야 할 때

- 프로그램 실행 도중 특정 조건에 따라 알고리즘을 변경해야 하는 경우

- ex) 결제 시스템(사용자가 결제 방식을 직접 선택하는 경우)

3. 코드 중복을 줄이고 유지보수성을 높이고 싶을 때

- 여러 개의 if문 또는 switch문을 제거하여 코드 중복을 줄이고 싶을 때

- 유지보수성을 높이고, 새로운 알고리즘(전략)이 추가될 때도 기존 코드 수정 없이 확장 가능

- 팩토리 패턴과 함께 사용 > 전략 객체를 생성하는 부분을 캡슐화 > if문 제거

- ex) 할인 시스템

4. 여러 객체가 같은 작업을 다른 방식으로 수행해야 할 때

- 여러 개의 객체가 같은 작업을 수행하지만, 방식이 다른 경우

- ex) 게임 캐릭터의 공격 방식(근접 공격 vs 원거리 공격)

5. 특정 기능이 계속 변경될 가능성이 클 때

- 특정 로직이 자주 변경될 것으로 예상될 때 미리 전략 패턴을 적용하면 유지보수성이 높아짐

- ex) AI 행동 패턴, 네트워크 요청 처리 방식, 로그 저장 방식


5. 전략 패턴과 팩토리 패턴을 함께 사용하기

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

// 2. 다양한 전략(결제 방법) 구현
class CreditCardPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println(amount + "원 신용카드 결제 완료!");
    }
}

class PayPalPayment implements PaymentStrategy {
    public void pay(int amount) {
        System.out.println(amount + "원 PayPal 결제 완료!");
    }
}

//*** 3. 팩토리 클래스 추가(전략을 생성 하는 역할)
class PaymentFactory{
    public static PaymentStrategy getPaymentStrategy(String type){
        switch(type.toUpperCase()){
            case "CARD": return new CreditCardPayment();
            case "PAYPAL": return new PayPalPayment();
            default: throw new IllegalArgumentException("잘못된 결제 방식" + type);
        }
    }
}

// 4. 결제 컨텍스트(Context) 클래스
class PaymentProcessor {
    private PaymentStrategy strategy;

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

    public void pay(int amount) {
        if (strategy == null) {
            System.out.println("결제 방식이 설정되지 않았습니다.");
            return;
        }
        strategy.pay(amount);
    }
}

// 4. 실행 코드 (Main)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        PaymentProcessor processor = new PaymentProcessor();

        System.out.println("결제 방식을 입력하세요 (CARD / PAYPAL):");
        String paymentType = scanner.next().toUpperCase();

        //팩토리 패턴을 사용하여 if문 없이 전략 설정 ~!
        processor.setPaymentStrategy(PaymentFactory.getPaymentStrategy(paymentType));

        processor.pay(5000);
    }
}
  • 팩토리 패턴과 함께 사용하면 if-else 문을 제거할 수 있다 !
    • 전략을 선택하는 로직을 별도의 클래스에 위임하면 if-else 없이 깔끔하게 전략을 설정할 수 있음
  • 팩토리 패턴 없이도 해결 가능하지만 유지보수성이 떨어짐..
    • Map을 활용하여 if문 없이 전략을 매핑할 수도 있지만, 새로운 전략을 추가할 때마다 직접 Map을 수정해야 함..

6. 결론

전략 패턴은 알고리즘을 캡슐화하여 실행 중에도 유연하게 변경할 수 있도록 설계하는 패턴이다.

 

OCP(개방-폐쇄 원칙)을 준수하여, 기능을 확장할 때 기존 코드를 수정하지 않아도 된다.

여러 개의 알고리즘(전략)을 정의하고, 실행 시점에서 적절한 전략을 선택하여 사용할 수 있도록 한다.

유지보수성과 확장성을 고려한다면 전략 패턴과 팩토리 패턴을 함께 사용하는 것이 가장 좋다 !

'Computer Science > Design Pattern' 카테고리의 다른 글

이터레이터 패턴(Iterator Pattern)  (0) 2025.03.21
프록시 패턴(Proxy Pattern)  (0) 2025.03.19
옵저버 패턴(Observer Pattern)  (1) 2025.03.19
팩토리 패턴(Factory Pattern)  (0) 2025.03.17
싱글톤 패턴(Singleton Pattern)  (1) 2025.03.14
'Computer Science/Design Pattern' 카테고리의 다른 글
  • 프록시 패턴(Proxy Pattern)
  • 옵저버 패턴(Observer Pattern)
  • 팩토리 패턴(Factory Pattern)
  • 싱글톤 패턴(Singleton Pattern)
zajinmori
zajinmori
hello world !
  • zajinmori
    zajinmori's DevLog
    zajinmori
  • 전체
    오늘
    어제
  • 글쓰기 관리
    • 전체 (14)
      • Computer Science (14)
        • Design Pattern (8)
        • Programming Paradigm (3)
        • Network (3)
        • Operating System (0)
        • Database (0)
        • Data Structure (0)
  • 블로그 메뉴

    • 링크

    • 공지사항

    • 인기 글

    • 태그

    • 최근 댓글

    • hELLO· Designed By정상우.v4.10.3
    zajinmori
    전략 패턴(Strategy Pattern)
    상단으로

    티스토리툴바