디자인패턴

전략 패턴 ( Strategy Pattern )

Romenest 2021. 8. 30. 22:07

전략 패턴 이란?

전략패턴은 알고리즘들을 정의하고 각각의 알고리즘을 *캡슐화 하여 알고리즘들을 같은 계열 안에서 교체하여 사용할 수 있는 패턴이다.

*캡슐화 : 외부에는 불필요하고 내부적으로만 사용되는 부분을 감추기 위해 속성이나 메소드를 사용자가 사용할 수 없도록 은닉화 한 것

범위를 최대한 좁힌다고 생각하면 된다. 캡슐화를 사용 하지 않을 경우 어디서나 호출가능한 함수가 있을 것이며 수정시 호출하고있는 곳 모두를 살펴봐야할 번거로움이 생긴다.

 

객체들이 할 수 있는 동작을 전략으로 만들어 필요할때 마다 교체하여 사용해 동작을 바꾸는 패턴이다.

전략패턴을 사용하게 된다면 *OCP(Open Closed Principle)에 위배 되지않고 기능을 추가 할 수있다.

*OCP : 개방 폐쇄원칙 

소프트웨어 구성 요소(컴포넌트,클래스,함수 등)은 확장에 대해서 개방되어 있어야하며 수정에 대해서는 폐쇄되어야한다. 즉, 기존코드를 변경하지 않고 기능을 추가할 수 있게 설계 하여야 한다는 말.

 

전략 패턴은 3가지 요소로 구성되어 있으며 이는

  • 전략 메소드를 가진 전략 객체
  • 전략 객체를 사용하는 컨텍스트(사용자/소비자)
  • 전략 객체를 생성해 컨텍스트에 주입하는 클라이언트

로 이루어져있다.

 

 

전략 패턴 예시

영화관을 예시로 들어봅시다.

L사 영화관은 A관은 10,000원의 영화비를 받고 B관은 15,000원의 영화비를 받는다고하자

간단히 작성하겠다

public class Movie {
  public void join();
}

public class Asite extends Movie {
  public void join() { System.out.println("A관은 10,000원입니다"); }
}
public class Bsite extends Movie {
  public void join() { System.out.println("B관은 15,000원입니다"); }
}

public class Client {
  public static void main(String[] args) {
    Movie Asite = new Asite();
    Movie Bsite = new Bsite();

    Asite.join();
    Bsite.join();
  }
}

결과

 

A관은 10,000원입니다
B관은 15,000원입니다

 

만약 L사 영화관이 평생 A관은 10,000원 B관은 15,000원을 유지하게 된다면 이는 간단하고 좋은 코드가 될 수 있다

그러나 A관에만 조조할인이 적용되거나 특별한 영화관 기념일에는 A,B관 모두 할인되거나 하는 정책이 생긴다면 해당 메소드들을 수정하기 어려워진다.

아래는 B관만 가격이 내려간 경우이다. 이는 OCP를 위반한 경우이다.

public class Asite extends Movie {
  public void join() { System.out.println("A관은 10,000원입니다"); }
}
public class Bsite extends Movie {
  public void join() { System.out.println("B관은 12,500원입니다"); }
}

만약 이때 새로 C관이 지어져 상영하게 되고 가격측정이 이루어진다면

분명히 결제방식은 같음에도 추가적으로 join()메소드를 사용하여 C관을 구현해야한다. 즉 코드 중복이 일어난다

public class Csite extends Movie {
  public void join() { System.out.println("C관은 20,000원입니다"); }
}

 

앞선 두가지 문제를 해결하기위해서 전략패턴을 이용해 가격측정을 별도로 분리 할 수 있다.

 

전략패턴 이용


public class movie {
private Price price;
public void join() { Price.join();}
public void discountjoin(Price price) {
	this.price = price;
	}
}

public class Asite extends Movie {
}
public class Bsite extends Movie {
}

interface Price { public void join(); }
public class MorningAsite implements Price {
	public void join() { System.out.println("조조할인된 가격 5,000원입니다") }
}
public class MorningBsite implements Price {
	public void join() { System.out.println("조조할인된 가격 7,500원입니다") }
}
public class AsiteJoin implements Price {
	public void join() { System.out.println("A관은 10,000원입니다") }
}
public class BsiteJoin implements Price {
	public void join() { System.out.println("B관은 15,000원입니다") }
}

public class Client {
	 public static void main(String[] args) {
      Movie Asite = new Asite();
      Movie Bsite = new Bsite();
      
      Asite.discountjoin(new AsiteJoin());
      Bsite.discountjoin(new BsiteJoin());
      
      Asite.join();
      Bsite.join();
      
      Asite.discountjoin(new MorningAsite());
      Bsite.discountjoin(new MorningBsite());
      
      Asite.join();
      Bsite.join();
      
      }
}

전략 패턴을 이용하지 않았을 때와 달리 기존 클래스는 건들지 않고 Price를 상속받아 사용하면된다.

 

결과

 

A관은 10,000원입니다
B관은 15,000원입니다

조조할인된 가격 5,000원입니다
조조할인된 가격 7,500원입니다

 

 

재정리

전략패턴은 컨텍스트(소비자,사용자) 가 사용할 수 있는 여러 변경 가능한 전략을 인터페이스를 이용해 캡슐화 하여

필요에 따라 교체, 수정하여 사용할 수 있도록 하는 디자인 패턴이다.