정책 패턴이라고도 불리우며, 객체의 행위를 바꾸고 싶은 경우 '직접' 수정하지 않고 전략이라고 부르는 '캡슐화한 알고리즘'을 컨텍스트 안에서 바꿔주면서 상호 교체가 가능하게 만드는 패턴이다.
사실 한 번에 이해가는 정의는 아니기에 예제 코드를 보면서 살펴보자
class Car {
constructor(type, pricingStrategy) {
this.type = type;
this.pricingStrategy = pricingStrategy;
}
getPrice() {
return this.pricingStrategy(this.type);
}
}
const sportsCarPricingStrategy = type => {
return type === "sports" ? 50000 : 0;
};
const sedanPricingStrategy = type => {
return type === "sedan" ? 35000 : 0;
};
const sportsCar = new Car("sports", sportsCarPricingStrategy);
console.log(sportsCar.getPrice());
const sedan = new Car("sedan", sedanPricingStrategy);
console.log(sedan.getPrice());
상기 예제를 조금 더 자세히 설명하자면, Car
이라는 클래스가 하나 만들어져 있고 이 클래스는 type
즉 자동차의 종류에 따라 pricing strategy
가 다르게 설정이 된다.
만약 sports
면 타입에 의거하여 메서드를 호출 했을 시 50,000이 반환 되고, 만약 sedan
이라면, 35,000이 반환된다.
이런 식으로 클래스 내부에 상황에 따른 메서드를 전략적으로 세분화 하여 실행시키는 디자인을 Strategy Pattern
이라고 한다.
대표적인 Strategy Pattern
이 적용된 사례로는 우리가 흔히 Authentication
관련 API를 구현할 때 쓰는 미들웨어 라이브러리인 PASSPORT
가 있다. PASSPORT
는 전략에 따라 Local Strategy
, OAuth
또는 OpenID Connect
를 사용 할 수 있다.
유연성 : 클래스 자체를 변경하지 않고 객체의 행위를 쉽게 바꿀 수 있게끔 알고리즘 호환이 자유롭다.
캡슐화 : 확장하는 것으로 객체를 캡슐화 할 수 있게되어 코드의 가독성이 좋아진다.
재사용성 : 다른 객체들에서도 알고리즘을 재사용 할 수 있기 때문에 유지 보수 및 에러 방지에 효과적이다.
테스트 용이 : 객체가 독립적으로 생성되기 때문에 테스트에 적합하다.
복잡성 : 알고리즘이 다양해 질수록 코드가 복잡해진다.
난이도 증가 : 전략 패턴을 사용한 다양한 알고리즘 사이에 관계 및 제어 흐름을 이해하기 어려울 수 도 있다.
어려운 디버깅 : 알고리즘이 다수의 클래스 및 함수들에 퍼져 있기 때문에, 디버깅이 어려울 수 있다.