Conceptly
← 전체 목록
🎯

Strategy

행동알고리즘을 캡슐화해 런타임에 교체할 수 있게 만드는 행동 패턴

Strategy 패턴은 같은 목적을 달성하는 여러 알고리즘을 각각 별도의 클래스로 분리하고, 사용하는 쪽(Context)이 그 중 하나를 선택해서 실행하는 구조입니다. 알고리즘을 쓰는 코드와 알고리즘 자체를 분리하기 때문에, 새 알고리즘을 추가하거나 기존 것을 바꿀 때 호출하는 쪽을 수정하지 않아도 됩니다.

아키텍처 다이어그램

🔍 구조 다이어그램

점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다

왜 필요한가요?

하나의 기능에 조건에 따라 다른 로직을 적용해야 할 때, 가장 자연스러운 첫 시도는 if-else나 switch문입니다. 결제 수단이 3개면 분기도 3개, 검증 규칙이 5종이면 분기도 5개가 됩니다. 여기에 새로운 방식이 추가될 때마다 같은 메서드 안에 분기가 하나씩 늘어나고, 기존 분기와 새 분기가 미묘하게 겹치면서 테스트 범위도 함께 부풀어 갑니다. 분기 하나를 고쳤는데 다른 분기가 깨지는 상황이 반복되면, 문제는 로직의 복잡성이 아니라 로직들이 한곳에 뭉쳐 있다는 구조에 있습니다.

왜 이런 방식이 등장했나요?

GoF가 Strategy를 패턴으로 정리한 1994년에도 이 문제는 이미 오래된 것이었습니다. 절차적 프로그래밍에서는 함수 포인터로 알고리즘을 교체했고, 객체지향 언어에서는 상속으로 행동을 바꿨습니다. 그런데 상속은 컴파일 시점에 고정되기 때문에 런타임에 알고리즘을 바꾸는 유연함을 주지 못했습니다. Strategy 패턴은 '상속 대신 합성(composition over inheritance)'이라는 설계 원칙의 대표적인 적용입니다. 현대 언어에서는 고차 함수, 클로저, 함수형 인터페이스가 Strategy를 더 가볍게 구현할 수 있게 해줬지만, '알고리즘을 교체 가능한 단위로 분리한다'는 핵심 아이디어는 변하지 않았습니다.

내부적으로 어떻게 동작하나요?

Strategy 패턴에는 세 역할이 있습니다. Strategy 인터페이스는 execute() 같은 공통 메서드를 정의합니다. 구체 Strategy 클래스들은 이 인터페이스를 구현하며 각각 다른 알고리즘을 담습니다. Context는 Strategy 인터페이스 타입의 필드를 갖고, 실행이 필요할 때 그 필드의 메서드를 호출합니다. 핵심은 Context가 구체 Strategy를 모른다는 것입니다. Context는 인터페이스만 의존하기 때문에, 어떤 알고리즘이 들어오든 같은 방식으로 호출합니다. 전략을 바꾸고 싶으면 Context에 다른 Strategy 객체를 주입하면 됩니다. 조건문이 사라지고, 대신 객체 조합으로 행동이 결정됩니다. 주의할 점은 전략이 서로 완전히 독립적이어야 한다는 것입니다. Strategy A의 결과가 Strategy B의 입력에 영향을 주는 식이면 Strategy 패턴이 적합하지 않을 수 있습니다.

무엇과 헷갈리나요?

Strategy와 State 패턴은 구조가 거의 같습니다. 둘 다 Context가 인터페이스에 실행을 위임하고, 구체 클래스를 교체할 수 있습니다. 차이는 의도에 있습니다. Strategy는 클라이언트가 목적에 맞는 알고리즘을 명시적으로 선택하는 것이고, State는 객체의 내부 상태에 따라 행동이 자동으로 바뀌는 것입니다. Strategy에서는 클라이언트가 어떤 전략을 쓸지 알고 있지만, State에서는 상태 전이가 내부에서 일어나므로 클라이언트가 인지하지 못할 수도 있습니다. Template Method와도 비교됩니다. 둘 다 알고리즘의 변형을 다루지만, Template Method는 상속으로 알고리즘의 일부 단계를 하위 클래스가 재정의하는 방식이고, Strategy는 합성으로 알고리즘 전체를 외부 객체에 위임하는 방식입니다. 런타임 교체가 필요하면 Strategy, 알고리즘 골격은 고정하고 세부 단계만 바꾸고 싶으면 Template Method가 맞습니다.

언제 쓰나요?

Strategy 패턴은 '같은 일을 다르게 처리하는 방식이 2개 이상이고, 앞으로 더 늘어날 수 있는가'라는 질문에 답이 예일 때 도입합니다. 결제 시스템에서 카드, 계좌이체, 간편결제 각각의 처리 로직을 Strategy로 분리하면, 새로운 결제 수단이 추가돼도 기존 결제 흐름 코드를 건드리지 않습니다. 설정이나 사용자 선택에 따라 런타임에 행동이 바뀌어야 하는 경우에도 적합합니다. 파일 내보내기에서 CSV, JSON, XML 포맷을 지원할 때, 각 포맷을 Strategy로 만들면 Context는 포맷에 무관하게 '내보내기'만 호출합니다. 반대로 알고리즘이 하나뿐이거나 변할 가능성이 낮다면 Strategy 패턴은 불필요한 추상화입니다. 분기가 2개인데 Strategy를 도입하면 클래스 수만 늘어나고 코드를 읽기 어려워질 수 있습니다. 패턴의 도입 시점은 '지금 분기가 몇 개인가'보다 '이 분기가 독립적으로 늘어날 축인가'로 판단하는 편이 낫습니다.

정렬 방식 교체결제 처리검증 규칙압축/직렬화