전략 패턴(Strategy Pattern)은 행위 디자인 패턴 중 하나로, 관련된 알고리즘 패밀리를 정의하고 각각을 캡슐화하여 상호 교체 가능하게 만듭니다. 이 패턴을 사용하면 알고리즘을 사용하는 클라이언트로부터 알고리즘을 독립적으로 변경할 수 있으며, 실행 중에 알고리즘을 동적으로 전환할 수 있습니다.
전략 패턴의 핵심 구성 요소:
- 전략 인터페이스(Strategy Interface): 모든 알고리즘이 구현해야 하는 공통 인터페이스를 정의합니다.
- 구체적인 전략 클래스(Concrete Strategy): 전략 인터페이스를 구현하는 실제 알고리즘 클래스입니다.
- 컨텍스트(Context): 전략 인터페이스를 사용하여 특정 전략 객체를 관리하고 실행합니다.
구현 예제:
검색 시스템에서 다양한 검색 방식(선형 검색, 이진 검색)을 구현하는 예제를 살펴보겠습니다.
먼저, 검색 전략 인터페이스를 정의합니다:
public interface SearchStrategy {
int search(int[] dataset, int target);
}
다음으로, 두 가지 구체적인 검색 전략 클래스를 구현합니다:
public class LinearSearchStrategy implements SearchStrategy {
@Override
public int search(int[] dataset, int target) {
for (int i = 0; i < dataset.length; i++) {
if (dataset[i] == target) {
return i;
}
}
return -1;
}
}
public class BinarySearchStrategy implements SearchStrategy {
@Override
public int search(int[] dataset, int target) {
int left = 0;
int right = dataset.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (dataset[mid] == target) {
return mid;
}
if (dataset[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
}
이제 검색 컨텍스트 클래스를 구현합니다:
public class SearchContext {
private SearchStrategy searchStrategy;
public SearchContext(SearchStrategy searchStrategy) {
this.searchStrategy = searchStrategy;
}
public void setSearchStrategy(SearchStrategy searchStrategy) {
this.searchStrategy = searchStrategy;
}
public int performSearch(int[] dataset, int target) {
return searchStrategy.search(dataset, target);
}
}
마지막으로, 클라이언트 코드에서 필요에 따라 다양한 검색 전략을 사용할 수 있습니다:
public class SearchDemo {
public static void main(String[] args) {
int[] data = {1, 3, 5, 7, 9, 11, 13, 15};
int targetValue = 7;
SearchContext searchContext = new SearchContext(new LinearSearchStrategy());
int result = searchContext.performSearch(data, targetValue);
System.out.println("선형 검색 결과: " + (result != -1 ? "요소가 인덱스 " + result + "에서 발견됨" : "요소를 찾을 수 없음"));
// 이진 검색 전략으로 전환
searchContext.setSearchStrategy(new BinarySearchStrategy());
result = searchContext.performSearch(data, targetValue);
System.out.println("이진 검색 결과: " + (result != -1 ? "요소가 인덱스 " + result + "에서 발견됨" : "요소를 찾을 수 없음"));
}
}
이 예제에서 SearchContext가 컨텍스트 역할을 수행하며 SearchStrategy 인터페이스에 의존합니다. LinearSearchStrategy와 BinarySearchStrategy는 구체적인 전략 구현체입니다. 클라이언트 코드는 SearchContext를 통해 다양한 검색 전략을 사용할 수 있으며, 검색 알고리즘의 변경이 클라이언트 코드에 영향을 주지 않습니다. 이는 개방-폐쇄 원칙(확장에는 열려 있고, 수정에는 닫혀 있음)을 준수하는 설계 방식입니다.
전략 패턴은 조건문(if-else 또는 switch-case)을 사용하여 다양한 알고리즘을 구현하는 대신, 알고리즘을 캡슐화하여 코드의 가독성과 유지보수성을 높이는 데 효과적입니다.