전략 패턴 적용
전략패턴
: 기존 인터페이스는 그대로 두고, 인터페이스를 구현하는 concrete strategy 추가해서 기능을 확장하는 구조
예)
🏰 마법의 레고 블록 상자 이야기
1. 레고 블록 상자가 하나 있어.
이 상자에는 네가 원하는 모양을 만드는 설계도(인터페이스)가 들어 있어.
설계도에는 “블록을 어떻게 조립할지”만 적혀 있어.
2. 그런데 설계도만으로는 장난감을 만들 수 없어.
진짜로 블록을 조립해 주는 마법의 도우미들이 필요해.
이 도우미들이 바로 “구체 전략 클래스”야.
3. 예를 들어, 공룡 레고를 만들고 싶으면
→ “공룡 설계도”를 따르는 공룡 도우미가 와서 블록을 조립해 주고,
우주선을 만들고 싶으면
→ “우주선 설계도”를 따르는 우주선 도우미가 와서 조립해 줘.
4. 네가 상자(컨텍스트)에 “오늘은 공룡을 만들어 주세요!”라고 말하면,
공룡 도우미를 불러서 블록을 조립하게 해.
“내일은 우주선을 만들어 주세요!”라고 하면
우주선 도우미를 부르면 돼.
전략패턴 만드는 법
1. strategy 인터페이스 선언
LottoStrategy 인터페이스 정의
public interface LottoStrategy {
List<int[]> recommend(List lottoData, int count, String ratioOption);
}
빈도 기반 추천
public class RecommendByFrequency implements LottoStrategy { … }
@override
public List<int[]> recommend(List lottoData, int count, String ratioOption)
기존에 LottoRecommend에 만들었던 빈도 기반 추천 코드들을 여기에 넣는다
무작위 추천
public class RecommendRandom implements LottoStrategy { … }
@override
public List<int[]> recommend(List lottoData, int count, String ratioOption)
이때 처음 LottoRecommend에서 RecommendRandom(int count)라고 해서 이때도 int count만 하면 안됨
인터페이스에 처음 선언된 대로 메서드 이름(recommend)과 파라미터 3개(List lottoData, int count, String ratioOption) 구현해야함
LottoContext 클래스 작성
public class LottoContext {
private LottoStrategy strategy;
public void setStrategy(LottoStrategy s) { this.strategy = s; }
public List<int[]> executeRecommend(List data, int count, String ratioOption) {
if (strategy == null) throw new IllegalStateException("전략 미설정");
return strategy.recommend(data, count, ratioOption);
}
}
LottoContext 라는 패키지와 클래스를 따로 만들어 준다
public class LottoContext {
private LottoStrategy strategy;
-> LottoStrategy 타입의 필드 선언
private이므로 외부 접근 불가
public void setStrategy(LottoStrategy s) { this.strategy = s;
-> 전략 주입(setter) 메서드
외부에서 LottoContext 에 실제 사용할 LottoStrategy 구현체(RecommendRandom, RecommendByFrequency) 를 넘겨주는 통로
s를 받아 내부 strategy 필드에 저장
LottoStrategy s
-> LottoStrategy 타입의 값을 하나 받아서 s 라는 이름으로 사용할게
s는 그냥 RecommendByFrequency, RecommendRandom 을 받기 위한 매개변수
s 자리에 new RecommendByFrequency()나 new RecommendRandomly()를 넣어 호출하면, s는 그 객체 참조를 받아서 this.strategy 필드에 저장해 주는 역할
this.strategy
-> this: 지금 이 메서드를 실행 중인 그 객체 자신
this.strategy : LottoContext 클래스의 필드 strategy를 명시적으로 참조
->외부에서 받은 전략 객체(s)를 이 객체의 내부 필드(this.strategy) 에 저장할게
public List<int[]> executeRecommend(List<LottoResult> data, int count, String ratioOption) {
if (strategy == null) throw new IllegalStateException("전략 미설정");
return strategy.recommend(data, count, ratioOption);
}
context.setStrategy(new RecommendByFrequency());
List<int[]> results = context.executeRecommend(loadedResults,10,"4:2");
.setStrategy : 어떤 전략 쓸거임?
.setStrategy(new RecommendByFrequency()) : 빈도 추천하는 전략으로
context.executeRecommend(loadedResults,10,"4:2");
-> strategy 설정되지 않았으면 예외, 되어있으면 data,count,ratioOption 호출