blog

디자인 패턴 이해하기 전략 패턴이란 무엇인가요?

전략 패턴이란 무엇인가요? 전략 패턴은 생활과 밀접한 몇 가지 예를 들자면, 여행할 때 걷기, 운전, 자전거, 비행, 크루즈 탑승 등 여행 모드에 따라 전략이 다르고, 각 여행 모...

Oct 24, 2025 · 5 min. read
シェア

전략 모델이란 무엇인가요?

전략 모드, 생활과 가까운 몇 가지 예를 들자면, 여행할 때 걷기, 운전, 자전거, 비행, 크루즈 탑승 등 여행 모드마다 다른 전략이 있고, 여행 모드마다 비용과 시간이 다르며, 쇼핑몰과 슈퍼마켓에 갈 때 할인을 받거나 할인을 받거나 포인트 환급 등 모든 전략이 전략입니다!

먼저 전략 패턴의 정의를 살펴 보겠습니다. 전략 패턴은 알고리즘을 서로 교체 할 수 있도록 개별적으로 캡슐화 된 알고리즘 제품군을 정의하므로 알고리즘이 변경되어 알고리즘을 사용하는 고객에게 영향을 미치지 않도록이 패턴을 정의합니다.

전략 패턴의 핵심은 자주 변경되는 포인트를 별도의 클래스로 추출하는 것이며, 각 클래스는 서로 교체 및 결합할 수 있으며, 클래스 다이어그램 관계는 다음과 같습니다:

전략 패턴의 클래스 다이어그램과 결합하면 전략 패턴은 추상 전략 클래스, 구체적 전략 클래스, 컨텍스트 클래스 또는 필수 매개 변수 클래스의 세 가지 주요 부분으로 구성된다는 것을 알 수 있습니다.

전략 패턴은 컨텍스트 클래스를 통해 취할 접근 방식을 자유롭게 선택합니다.

public class AbstractContext {
 AbstractStrategy strategy;
 //특정 전략 개체에 전달된 초기화
 public AbstractContext(AbstractStrategy strategy) {
 this.strategy = strategy;
 }
 //컨텍스트 인터페이스, 전략의 특정 메서드 호출
 public void ContextInterface() {
 strategy.ItsInterface();
 }
}

그리고 해당 메서드는 모두 동일한 추상 전략 클래스에서 상속됩니다:

public abstract class AbstractStrategy {
 //하위 클래스에 맡겨서 자체적으로 구현할 수 있습니다.
 public void ItsInterface(){
 }
}

특정 전략 클래스 구현은 다음과 같이 하위 클래스에서 오버로드됩니다:

public class FakeStrategy extends AbstractStrategy{
 
 @Override
 //특정 메서드의 서브클래스 구현
 public void ItsInterface() {
 System.out.println("I'm using this method");
 }
}

구체적인 구현

전략 패턴이 해결하고자 하는 문제는 주로 여러 알고리즘이 매우 유사한 경우 객체가 컨텍스트에 따라 구현에 맞는 선택을 할 수 있도록 하는 것입니다. 예를 들어 첫 단락에서 언급했듯이 자전거, 운전, 걷기 등 외출 방법을 선택하거나 잠시 자전거를 타고, 잠시 걷고, 잠시 비행기를 타는 것과 같은 경우입니다.

'빅토크 디자인 패턴'에서 제시한 예시가 매우 적절하다고 생각하는데요, 쇼핑몰이 프로모션 활동을 하고 있고, 할인 활동, 전액 할인 활동이 있으며, 할인의 강도와 전액 할인의 범위는향후 수정이 필요할 수 있는데 전체 시스템을 어떻게 설계해야 할까요?

전략 패턴 구현

이제 쇼핑몰에 정상 정산, 할인 정산, 리베이트 정산의 세 가지 정산 방식이 있다고 가정해 보겠습니다. 전략 모델의 아이디어에 따라 다음과 같이 시스템을 설계할 수 있습니다:

  • 컨텍스트 클래스(컴퓨팅)

먼저 추상 컨텍스트 클래스를 생성하고, 수신 전략 클래스를 기반으로 특정 오퍼 전략을 가져온 다음, getPrice()를 호출하여 최종 지불 결과를 얻습니다.

public class CashContext {
 private CashAbstract CashAbstract;
 public CashContext(CashAbstract CashAbstract) {
 this.CashAbstract = CashAbstract;
 }
 public double getResult(double money) {
 return CashAbstract.acceptCash(money);
 }
}
  • 추상화 전략 클래스

이 경우 추상 전략 클래스는 쇼핑몰 활동과 고객이 지출한 금액을 기준으로 실제로 지불해야 하는 금액을 계산하는 것을 말합니다:

public abstract class CashAbstract {
 public abstract double acceptCash(double money);
}
  • 세 가지 특정 전략 하위 클래스

쇼핑몰 활동에는 정상 청구, 할인 청구, 리베이트 청구의 세 가지가 있으며 여기에서는 리베이트 청구에 대한 구현만 설명합니다:

public class CashReturn extends CashAbstract {
 //리베이트 청구, 초기화에는 리베이트 조건과 리베이트 금액을 입력해야 합니다.
 private double moneyCondition = 0.0;
 private double moneyReturn = 0.0d;
 public CashReturn(double moneyCondition, double moneyReturn) {
 this.moneyCondition = moneyCondition;
 this.moneyReturn = moneyReturn;
 }
 @Override
 public double acceptCash(double money) {
 double result = money;
 if (money >= moneyCondition) {
 result = money - Math.floor(money / moneyCondition) * moneyReturn;
 }
 return result;
 }
}
  • 설계된 충전 시스템 테스트
public class App {
 public static void main(String[] args) {
 CashContext cashContext = null;
 Scanner scanner = new Scanner(System.in);
 System.out.print("활동을 입력하세요: 1은 일반 청구, 2는 리베이트 청구, 3은 할인 활동");
 int in = scanner.nextInt();
 String type = "";
 switch (in) {
 case 1:
 cashContext = new CashContext(new CashNormal());
 type += "일반 요금";
 break;
 case 2:
 cashContext = new CashContext(new CashReturn(300, 100));
 type += "전체 300 반환 100";
 break;
 case 3:
 cashContext = new CashContext(new CashRebate(0.8));
 type += "20% 할인";
 break;
 default:
 System.out.println("1/2/3을 입력하세요.");
 break;
 }
 double totalPrices = 0;
 System.out.print("단가를 입력하세요:");
 double price = scanner.nextDouble();
 System.out.print("번호를 입력하세요:");
 double num = scanner.nextDouble();
 totalPrices = cashContext.getPrice(price * num);
 System.out.println("단가:"+ price + ",번호:"+ num + ",유형:"+ type + ",합계:"+ totalPrices);
 scanner.close();
 }
}

정상적인 활동 패턴:

리베이트 캠페인 모델:

할인된 활동 패턴:

보시다시피 설계된 충전 시스템은 괜찮습니다.

전략 패턴 + 심플 팩토리

하지만 위의 전략 패턴 구현은 잘 작동하고 현재 요구 사항을 충족합니다. 하지만 오류가 없는 코드가 더 좋을까요? 물론 아닙니다!

생각해보니 위 코드의 구현 라인을 따라 새 활동 카테고리를 추가하는 경우에도 스위치 케이스 종류에 브랜치를 추가해야 하지 않을까요?

또한 클라이언트 코드는 현금 컨텍스트와 현금 노멀, 현금 리턴, 현금 리베이트 등 여러 객체와 '결합'되어 있습니다. 클라이언트 측에서 결합된 객체가 많을수록 수정 및 확장하기가 더 어려워집니다.

세 가지 팩토리 패턴을 소개할 때 이런 종류의 스위치 케이스 문이 발생할 때 간단한 팩토리 패턴을 사용하여 문제를 해결하거나 리플렉션을 통해 코드를 단순화할 수 있다고 언급했습니다.

여러분도 한번 사용해 보시겠어요?

요약

전략의 장단점부터 살펴보겠습니다:

전략 패턴의 장점은 사용할 알고리즘을 유연하게 선택하고 ifelse 문을 줄일 수 있다는 점입니다;

단점은 구체적인 정책 클래스가 있는 경우 개별 정책 클래스 간에 재사용이 불가능하다는 것입니다.

구체적인 애플리케이션 시나리오는 어떻게 되나요?

알고리즘 전환이 필요하고 알고리즘 간에 구현상의 차이만 있으며 나머지 매개 변수는 추상화하여 공유할 수 있는 시나리오입니다.

Read next

파이썬과 파이게임으로 게임을 만들어 보세요:

이 장에는 4개의 추가 게임에 대한 소스 코드가 포함되어 있습니다. 아쉽게도 이 장에는 소스코드만 포함되어 있으며 코드에 대한 자세한 설명은 포함되어 있지 않습니다. 지금까지는 소스 코드와 코멘트를 보면서 이 게임들을 플레이하고 코드가 어떻게 작동하는지 알아볼 수 있습니다. 이 게임들은 다음과 같이 패키지로 제공됩니다.

Oct 24, 2025 · 102 min read