전략 패턴은 여러 알고리즘을 별도의 개체에 캡슐화하고 런타임에 상호 교환 가능하게 만드는 방법을 제공하는 디자인 패턴입니다. 패턴의 목적은 클라이언트가 알고리즘의 구현 세부 사항을 알 필요 없이 특정 작업에 가장 적합한 알고리즘을 선택할 수 있도록 하는 것입니다.
전략 패턴에서 알고리즘은 개체로 정의되며 클라이언트는 공통 인터페이스를 통해 알고리즘과 상호 작용합니다. 클라이언트는 성능이나 기능과 같은 일부 기준에 따라 사용할 알고리즘을 선택할 수 있습니다. 즉, 클라이언트는 시스템에 영향을 주지 않고 런타임에 사용되는 알고리즘을 변경할 수 있습니다.
전략 패턴은 알고리즘을 시스템의 다른 부분에서 사용하며 시스템의 나머지 부분에 영향을 주지 않고 쉽게 확장하거나 수정할 수 있어 모듈성과 재사용성을 촉진합니다.
클라이언트가 특정 작업에 가장 적합한 것을 선택하고 쉽게 전환이 가능합니다. -> 유연성 향상
요약해서 말하면 전략 패턴은 복잡한 알고리즘을 구현하거나 복잡한 논리를 캡슐화하기 위한 유연한 모듈식 솔루션을 제공합니다. 따라서 소프트웨어 시스템의 설계를 개선하기 위해 다양한 상황에 적용이 가능합니다.
다양한 가격 책정 전략에는 일반가, 할인가, 특가 등 가격 계산을 위한 서로 다른 알고리즘이 있습니다. 전략 패턴은 해당 알고리즘을 캡슐화하고 상호 교환 가능하게 만드는데 사용할 수 있습니다. 시스템이 사용자 요구 사항에 따라 런타임에 가격 책정 전략간에 전환할 수 있습니다.
위의 예시는 간단한 예시지만 실제로는 결제 게이트웨이, 로깅, 압축, 정렬 등등 다양한 곳에서 쓰이고 있습니다.
서로 다른 알고리즘에 대해 여러 객체를 생성하고 관리해야 하므로 시스템 전반적인 복잡성을 증가시킬 수 있습니다. -> 가독성 떨어짐, 유지 보수 어려움
유사한 알고리즘이 서로 다른 전략 개체에서 여러 번 구현된다면 변경 사항을 모든 복제본에 전파해야 하는 상황이 올 수 있습니다. -> 코드 중복 및 유지 관리 문제, 성능 오버헤드도 야기할 수 있다.
하지만 이러한 단점은 우수한 설계 및 구현으로 극복할 수 있습니다. 모듈성, 유연성, 재사용성과 같은 전략패턴의 이점을 적절하게 사용하면 됩니다.
가격 측정 전략 패턴
interface PricingStrategy {
double getPrice(double originalPrice);
}
class RegularPricing implements PricingStrategy {
public double getPrice(double originalPrice) {
return originalPrice;
}
}
class DiscountPricing implements PricingStrategy {
public double getPrice(double originalPrice) {
return originalPrice * 0.9;
}
}
class SalePricing implements PricingStrategy {
public double getPrice(double originalPrice) {
return originalPrice * 0.75;
}
}
class Item {
private String name;
private double price;
private PricingStrategy pricingStrategy;
public Item(String name, double price, PricingStrategy pricingStrategy) {
this.name = name;
this.price = price;
this.pricingStrategy = pricingStrategy;
}
public double getPrice() {
return pricingStrategy.getPrice(price);
}
}
public class Main {
public static void main(String[] args) {
PricingStrategy regularPricing = new RegularPricing();
PricingStrategy disCountPricing = new DiscountPricing();
PricingStrategy salePricing = new SalePricing();
Item regularItem = new Item("notebook", 2999, regularPricing);
Item disCountItem = new Item("notebook", 2999, disCountPricing);
Item saleItem = new Item("notebook", 2999, salePricing);
System.out.println("notebook price : $" + regularItem.getPrice());
System.out.println("notebook price : $" + disCountItem.getPrice());
System.out.println("notebook price : $" + saleItem.getPrice());
}
}
Item이라는 클래스에 이름, 가격, 가격 측정 전략을 지정하여 클래스의 인스턴스를 만들었습니다. getPrice메서드를 호출하면 가격 책정 전략에 따라 가격이 반환됩니다.
해당 예시는 간단하지만 서로 다른 알고리즘을 별도의 클래스에 캡슐화하고 런타임에 상호 교환 가능하게 만드는 것이 전략 패턴입니다.