SIDE)특정객체에 정책적용
특정 객체에 정책을 적용하는 2가지 방법
📜 제목으로 보기
- 준비물(정책 조건과 액션)
- method1: trigger+action의 인터페이스 + 마커 인터페이스
- method2-1: 전략condition을 머금은 템플릿policy
- method2-2: 템플릿policy를 일반class + 전략policy로 변환(2개의 전략객체를 사용하는 일반policy)
- method2-3: policy전략객체마다 위임&캐싱된 policy전략Factory 생성
준비물(정책 조건과 액션)
- 정책 조건과 액션 종류
- 조건(-Condition)
- Sequence: 순서에 해당한다는 조건(혹은 선착순 몇명 안에 조건)
- Period: 특정 기간내에 해당한다는 조건(혹은 특정기간에 드는 조건)
- DayOfWeek: 특정 요일에 해당한다는 조건
- None: 조건없이 시행
- 액션(-Discount)
- Amount: 일정 금액을 Discount해준다.
- Percent: 일정비율을 Discount해준다.
- None: 할인 없음.
- 조건(-Condition)
method1: trigger+action의 인터페이스 + 마커 인터페이스
설명
-
정책 condition 인터페이스: trigger와 action추상메서드를 다 가질 것임.
- 발동조건 검증 메서드 역할(추메)
- 액션 메서드 역할(추메)
-
정책 action 인터페이스: 마커인터페이스들을 내부에서 가짐.(enum과 비슷한 역할)
-
enum대신 인터페이스 속 마커 인터페이스들로 구성 됨.
-
마커인 이유: 실제 정책내용을 같이 붙어다니는 조건 정책의 액션메서드에서 실제 정책내용을 구현할 예정
-
정책 trigger 인터페이스가 2개의 추상메서드(trigger, action)을 다 가진다.
-
정책action마커인터페이스를 구현한
정책action별 중간추상층(추상class)
을 두어 1개의 추상메서드만 구현한다.- 이 때,
특정 action마커인터페이스 구현 && action메서드를 먼저 구현
한 중간추상층으로 만들어야
- 이 때,
-
정책을 적용할 객체
생성시,특정 action 중간추상층 알도록(T자리에 대체)
한 최종구상체를 선택하여action이 적용된 객체
를 생성할 수 있게 된다. -
제네릭을 통해, 특정action추상층을 알게된
정책적용객체
는제네릭으로 알게된 만큼, 그 추상층를 생성자 인자
로 사용하여, 생성자에서구상체
들을 받을 수 있게 된다. -
action별 중간추상층마다
condition별 최종구상층
을 만들어서, condition메서드를 구현하여 구상화한다.
-
-
-
my)
-
각각이 추상메서드로 가지는 인터페이스로 구현했다면?
- DiscountPolicy인터페이스에 action메서드가 올라가며
- DiscountCondition인터페이스의 trigger메서드도 같이 implements하여
- 최종구상체는 2개의 메서드를 구상하게 된다.
- 하지만, movie마다 특정 action정책을 줘야하는 카테고리화를 못한다(action별 추상층이 없다)
- movie가 특정action에 대한 여러 condition들을 동시에 인자로 받을 수 없다(action별 추상층이 없다.)
-
action X condition의 조합의 상태에서,
- 2가지 중 1가지로 카테고리화하려면, 추상층이 2개(action -> condition or condition -> action)여야하며
- 카테고리 대상(action)인터페이스를 먼저 구현하는 중간추상층이 필요하다.
- 조합의 나머지(condition)은 구상층에서 구현한다.
- 상위 추상층은 2개의 메서드를 가지는 1개(DiscountCondition)로도 충분하지만
- 1개 메서드를 구현한 중간추상층을 만들 때,
중간추상층별 나는 특정action 상층이다!
를 나타내줄마커인터페이스들
이 필요하다.
-
실습
Action 중간추상층 1개 -> Condition+Action 최종구상체 1개 생성
-
정책을 적용할 객체를 정책주입 없이 먼저 구현한다.
-
내부 정책이 적용될 대상메서드 등이 다 구현되어있어야한다.
-
-
적용할 정책을 설계해보기 위해, client에서 그림을 그려보기
-
정책적용은 action(어떤 할인 적용할지) vs condition(어떤 조건에 적용할지) 2가지 카테고리가 있는 상태다
- 각 카테고리마다 나올 2가지 전략메서드를 한개의 인터페이스에 몰아넣는다 생각한다.
- 먼저 1개는 중간추상층엑에서 구현 -> 나머지 1개는 최종구상체에 이름을 추가하여 구현한다고 생각한다
-
먼저 구현할 카테고리의 종류마다 -> 나머지 카테고리들을 가지게 된다고 생각한다.
- action을 먼저 구현한다면
-
AmountDiscount, PercentDiscount (중간추상층 2개)
- aAmountDiscount, bAmountDiscount, cAmountDiscount,dAmountDiscount (각 중간추상층 마다 4개)
- aPercentDiscount, bPercentDiscount, cPercentDiscount,dPercentDiscount (각 중간추상층 마다 4개)
-
AmountDiscount, PercentDiscount (중간추상층 2개)
- action을 먼저 구현한다면
- 그렇다면, 2가지 카테고리 중
어느 카테고리를 먼저 선택
할 것인지에 따라중간추상층으로 먼저 구현
하게 한다고 생각한다 - 정책적용 객체는
중간추상층을 upperbound
로 제네릭을 적용하여 ->해당 중간추상층을 구상체들만
알고서 인자/파라미터에 받을 수 있게하여해당 카테고리의 1개만 적용
할 수 있게 한다고 생각한다.
-
아래의 예시는
-
action으로 먼저 카테고리화하고, 각 action마다 중간추상층을 만들 것이다.
-
제네릭에 action중간추상층을 사용하면, 내부 T로 정의한 변수들은 중간추상층의 구상체들만 올 수있게 되므로, 해당action에 대한 condition들을 선택하여 집어넣을 수 있다.
-
-
정책적용은 action(어떤 할인 적용할지) vs condition(어떤 조건에 적용할지) 2가지 카테고리가 있는 상태다
-
먼저 적용할 카테고리인 action 중에 1개의 중간추상층과 condition 중 1개를 추가반영한 최종구상체 1개를 반영해 빨간줄로 만든다.
-
최종구상체를 먼저 만들고 -> extends 중간추상층 -> impl 상위추상층
DiscountCondition
을 만든다.- 상위추상층의 이름이 Condition인 이유는, **중간추상층에 action을 구현했다는 마커인터페이스를 DiscountPolicy 내부에서 만들것 이기 때문 **
-
최종구상체를 먼저 만들고 -> extends 중간추상층 -> impl 상위추상층
-
최종구상층 1개 -> 중간추상층 중 1개 ->
action+condition 전략메서드 2개를 달 예정인, 상위 추상층 DiscountCondition
-> action마커인터페이스를 순서대로 틀만 만든다.-
최종구상층을 1개를 먼저 만들되, 중간추상층을 상속하도록 만들고, 중간추상층도 상위추상층 DiscountCondition을 implements하도록 만든다.
-
사용 제네릭의 빨간줄을 해당class정의부에 T로 만들어주는 기능은 없다. ->
생성자에 파라미터 추가
를 이용해 해당 제네릭에 최종구상체의 추상체인 중간추상층이 들어가도록특정형 T -> upperbound 상위추상층
으로 내부에 정의해서빨간줄제네릭을 해결
하도록 해야한다.-
하지만, 제네릭 빨간줄 때문에 생성자 자동생성이 안된다. 잠시 지웠다가, 생성자에
T형(사용시 중간추상층 들어갈 예정) 파라미터로 들어가는 전략객체
를 추가하고,T upperbound 상위추상층
으로 정의 한뒤 사용제네릭을 다시 넣어주자.-
T에는 최종구상체들의 추상체인
[중간추상층들이 사용]될 수 이도록 T type 파라미터 -> [T의 upperbound에 상위추상층]
으로 지정해줘야한다.- 사용되는 제네릭 중간추상층은
T 정의시 직접적으로 사용X upperbound에 의해 결정
되는 것이 제네릭의 특징
- 사용되는 제네릭 중간추상층은
- 최종구상체들의 파라미터를 T로 정의하여 생성자 인자 추가때, change signature에 추가 되는 인자에 대해 최종구상체 1개 deafult value로 들어가면 related problem들이 알아서 해결됨.
-
T에는 최종구상체들의 추상체인
-
하지만, 제네릭 빨간줄 때문에 생성자 자동생성이 안된다. 잠시 지웠다가, 생성자에
-
생성자에 주입받은 정책용 전략객체를 필드로 받아준다.
-
-
이제 정책적용에 필요한 2가지
전략메서드를 사용하면서 하나씩 정의
하고 올려준다.-
할인정책을 적용할 메서드(calculateFee) 내부에서
-
정책 적용전 로직은 그대로 두고, early return을 활용하여
정책적용시 변화가 생길 field
를 action메서드의 인자로 +정책조건에 판단정보의 field
를 trigger메서드의 인자로받아가며 아래와 같이 정의해준다.- if 정책객체.isStatisFiedBy()를 사용하여 정책 조건trigger메서드를 사용하고
-
if내부 early return에
기존 반환값 로직
에서정책을 적용하여 바뀔 부분
과나머지 로직
을 나눈 뒤,정책 적용 대상
만 정책 적용action메서드의 인자로 사용한다. 이 때, 정책적용전 메서드 이름을 가져온다.
-
-
-
빨간불로 최종구상체에서 작성한 2개의 전략메서드 create method
하면중간최상층을 지나 바로 -> 상위추상층(인터페이스)에 알아서 오페이터로 작성
된다.- 최종구상체 : isSatisfiedBy의 2번째 카테고리(Condition)만 개별구현할 예정
- 중간추상층 : calculateFee의 1번째 카테고리(Policy)만 개별구현할 예정
- 이 때, 중간추상층마다 가질 action별 마커인터페이스를 달아줄 예정
-
중간추상층
은 2개의 오페이터 중action 메서드만 먼저 구현
하고,최종구상층
은 나머지trigger 메서드
를 구현한다.-
중간추상층은 에서 action메서드 구현시,
정책 적용에 필요한 정보
들은추상클래스의 생성자주입
으로 해결하고,나중에 최종구상체들이 그 생성자주입부 + 필드를 super()로 물려받아 구상체 생성시 받아서 부모에게 넘겨준다
-
주의
! 중간추상층은추상층으로서 개별구현이 구현되면 반드시 final로 자식이 못건들이게 막자
->추상층에 구현된 개별구현 method + 사용된 field
-
-
최종구상체는
실제 외부Client에서 생성되고, 값을 받아들이는 놈
으로서부모의 생성자주입에 필요한 값을 자식이 대신 받아
super()
를 통해 부모선에서 처리되도록 던져준다. -
최종 구상체는 2개 전략메서드 중 1개인
정책조건trigger메서드를 구현
하며, 필요한 것이 있으면 생성자로부터 받아서 정의한다.- Sequence -> Treatment정보에 찍혀있으며,
외부에서 입력해줄 선착순 sequence명
에게만 적용되는 정책조건이라고 가정하자.
- Sequence -> Treatment정보에 찍혀있으며,
-
최종구상체의 주입을 받는 부분에서, 최종구상체의 생성자주입 인자 중간추상층(부모)용 1개 + 최종구상체용 1개 의 인자가 늘어나므로 deafult값을 미리 명시해놓고 주거나 안꼬이게 할려면, 미리 NONE정책으로 구현했어야할 듯 하다.
-
ctrl+F6
으로 생성자에서 Sequence를 삭제후 바로 정책조건에 만족 안되는 값을 default로 주기- 중간추상층에 default값을 주면,
최종구상층에 적용
되어버리니 하지말기 super()에 들어갈 부모를 위한 생성자인자
도최종구상층에서 지웠다가 default값과 함께 추가
하기
- 중간추상층에 default값을 주면,
-
-
중간추상층의 abstract class에
Discountpolicy 카테고리인터페이스 > 개별 마커인터페이스
로 1개 카테고리의 개별종류 표시하기- Amount외에 Percent, Count, None 등의 할인정책action들이 있다.
-
메서드가 없는 마커인터페이스를 만들고, 하위 최종구상체들을 묶어줄 카구체 테고리를 표시한다.
-
현재 Condition X policy의 조합인데, 인터페이스가 그만큼 명시되어있어야하며, Amount계열/Pecent계열의 최종구상체를 묶어서 한번에 처리할 수 있다?
- 추상클래스론 안되는가??
-
현재 Condition X policy의 조합인데, 인터페이스가 그만큼 명시되어있어야하며, Amount계열/Pecent계열의 최종구상체를 묶어서 한번에 처리할 수 있다?
-
DiscountPolicy의 카테고리 인터페이스를 만든다.
-
인터페이스 내부에서 마커인터페이스들을 만든다.
- 인터페이스 내부 인터페이스는
상위인터페이스{}
를extends
하여 구현한다.
- 인터페이스 내부 인터페이스는
-
완성된 action중간추상층에 마커인터페이스를
추가 impl
한다.- extends상속은 1개만 되지만,
- 카테고리 인터페이스의 implements는 콤마로 여러 개 할 수 있다.
-
중간추상층의 제네릭사용
을 위한정책적용객체(Specialty)
의제네릭정의부 T의 upperbound
를 중간추상층의 상위추상층을 줘야하는데, 1개더 추가되었을 땐,<T extends A & B>
형태로& 추가인터페이스
를 주면 된다.
-
완성된 discountpolicy 관련 파일들을
discountpolicy패키지로 이동
시키고,개별 action중간추상층별로 패키지를 만들어서 관리
한다.
최종구상체들추가 Condition+Action
-
이제
AMOUNT계열
의 Sequnce Trigger외 다른condition들을 반영한최종구상체들
을 늘려간다.-
AmountDiscount라는 중간추상층(추상클래스)가 인터페이스 2개와 1개의 전략메서드를 구현하고 있으니, 최종구상체는 추상클래스 1개 상속 및 super()에 전달위한 인자 생성자 주입만 해주면 된다.
- Sequence 조건외에
Period
,Weekend
이 남았음
- Sequence 조건외에
-
추가된 2개의 AMOUNT계열 최종구상체의 trigger메서들 구현한다
-
DayOfWeekAmountDiscount
PeriodAmountDiscount
Action 중간추상층 추가
-
action을 구현한 action 중간추상층은 아래과 같이 형성되어있다.
- package로 따로 분리해서, 하위에 condition을 단 최종구상체들이 오도록 한다.
- 2개의 오퍼레이터를 가진 상위추상층 DiscountPolicy와 action에 대한 마커인터페이스 DiscounPolicy.XXXX 2개의 인터페이스를 구현한 추상클래스로 만든다.
- action메서드 구현에 필요한 것은 생성자 주입으로 받는다.
- 추상메서드(오페레이터, 전략메서드)에서는 이미 시그니쳐가 정해져있음.
PercentDiscount
NoneDiscount
OverlappedDiscount -> 불가. action 1개당 1개의 condition만 배정되는 상태
- 현재 movie에는 1개의 action - 1개의 condition이 반영된 최종구상체만 들어간다.
- 만약, 1개의 action을 여러번 적용하려면,
정책적용 객체
가여러개의 정책객체를 받도록
해당계열 최종구상체들을 가변배열
로 여러개 받게 한다.
- 만약, 1개의 action을 여러번 적용하려면,
정책적용 객체(Specialty)가 여러 정책객체(최종구상체)를 가지게 하기
-
action과 trigger를 동시에 가지는 정책객체이므로 여러 trigger를 돌면서 fee객체에
만족시마다 여러번 정책 적용
시키도록,생성자 주입 정책객체를 가변배열로 여러개
받도록 수정하기-
변경전
-
-
생성자 파라미터를
...
가변배열로 바꾼다. -
필드를 빈 Set으로 바꾼다.
-
생성자에서 배열 -> List -> addAll 으로 초기화해준다.
-
여러개의 정책객체를 for문으로 돌면서, 만족할때마다 적용시켜주며,
누적 적용에 대한 코드
를 작성한다.-
.multi(count)
는 1개당 가격에 정책이 다 적용된 뒤 곱해야한다. - 여러개가 누적되서 적용이므로 누적적용용 재할당 누적변수를 for문 위에 만들어놓는다.
- 내부에서 trigger를 만족할때마다 누적변수에 적용 후 누적변수에 재할당한다.
- 마지막에 정책적용후 로직인
.multi(count)
를 적용한다.
-
method2-1: 전략condition을 머금은 템플릿policy
설명
-
참고 내 블로그object_part1_summary.html#discountpolicy-1)
-
as-is
-
to-be
-
기존 discountpolicy 관련 로직을 다 삭제함
실습
-
정책적용 대상 객체(Specialty)에
action policy(템플릿)의 구상체부터 시작
하되,step1의 2개 인터페이스 조합 -> action중간추상층을 생성 -> 특정 중간추상층을 사용하기 위한 제네릭
이 필요 없다.- 직전: 최종구상체 SequenceAmountDiscount -> action 중간추상층 AmountDiscount -> 그외 action추상층들을 제네릭으로 선택해야, 그 하위 condition조합된 최종구상층들을 받을 수 있었음.
- 현재: condition전략을 선택해서 받은 action템플릿의 자식1개만 알면 된다.
- 조합으로 인해 생긴 중간추상층이 없음 -> 제네릭 필요 없음.
- 생성자 인자 추가시
change signature -> default value
를 활용한다.- 기존에 생성되어 사용되고 있는 객체면, 자동으로 defaultValue 지정 change signature가 뜸.
-
정책적용대상 객체 내부
에서, 생성자로 받은action템플릿 객체를 사용
해서 ->추상체 변수로 받으면서 추상클래스 생성
+public 템플릿메소드를 빨간줄로 완성
해보자.- action템플릿메소드는
정책적용 필드
뿐만 아니라내부에 머금을 condition을 위한 조건정보(treatment, count)
도 같이 건네줘야한다.
-
템플릿 추상층만 만들었으니, 연결해준다.
- 훅메서드를 만들어서 올리는 구조가 아니라서 직접 상속해준다.
- action템플릿메소드는
-
action템플릿을 작성할 때, 구상체로부터 올리는 것은
@Override + protected 훅메서드
밖에 없으니템플릿메소드부터 직접 작성
해준다-
여기서 템플릿action에서는
여러개의 condition전략객체들
을 알고 있다고 가정한다.- 여러 조건들을 다 적용시킬 예정
템플릿 메소드 내에서 훅메서드 만드는 방법
은내수용 private메서드로 작성
해서proteced abstract
로 빼야한다.
- conditions들을 반복문 돌리려면, DiscountCondition전략인터페이스 생성 -> 빈컬렉션으로 초기화 한다.
- condition의 trigger전략메서드를 사용하면서 정의한다.
- 개별action적용을 위해
내수용 메서드(객체없이 정의)
를 통해정책을 적용할 필드(객체)에 훅메서드를 건다
. - 누적 적용을 위해서, 초기값(fee 파라미터)을 누적용 변수에 넣고, 누적용 변수에 적용해서 반복문 안에서 재할당한다.
- 적용된 객체를 반환한다.
-
여기서 템플릿action에서는
-
템플릿policy를 직접 작성하여 내부 훅이 정의 (by 내수용 메서드)되었으면, 구상policy에서 훅을 구현하여 완성한다.
-
action템플릿(추상클래스)도
condition전략객체를 생성자 주입
하는데conditions가 여러개면서 유연하게 받으려면 빈컬렉션 초기화+ void setter(add)를 이용
한다-
여러 전략객체들을 받으며
-> 빈컬렉션 필드- 빈컬렉션으로 초기화한 순간 생성자에 자동주입은 안된다.
생성자에서도 받아서 add
하도록 시킬 수 있는데, 이럴 경우생성시 반드시 입력해야해서 유연성이 사라져버린다는 단점
이 생긴다.
-
policy 생성후에도 condition들을 유연하게 추가
-> ( setter->add) -
외부에서는 지역변수로 미리 생성해놓고고 condition전략객체들을 add해서받는다.
-
-
구상 템플릿policy -> 추상 템플릿policy -> 구상템플릿policy 완성 -> 추상 전략condition -> 구상 전략condition순서로 개발 중이다.
-
구상condition을 추상condition 변수자리에 넣어 사용하면서 만든다.
- 구상 전략객체를 개별정의시, 역시 필요한 정보는 생성자 주입 받는다.
-
-
전략condition 객체 1개와 전략condition을 먹금은 템플릿policy 구상체 1개가 만들어진 상태다.
-
전략Condition과, 템플릿Policy가 따로 관리되므로
package를 분리
해준다.
-
-
만들어진 구상체들을 테스트해준다.
-
가장 하위계층에 있는 condition을 테스트하고 -> condition을 먹금은 템플릿policy을 테스트하는 순서대로 진행한다.
-
템플릿의 구상체는
상속된 자식
으로서 개별구현하는훅메서드
이외에보이지 않는 템플릿메소드 및 추상클래스에 정의한 필드 + 메서드들
을 활용해야한다.
-
-
남은 전략Condition객체 생성
-
PeriodCondition
-
DayOfWeekCondition
-
-
남은 템플릿policy 구상체들 생성. 템플릿의 구상체들은 훅메서드만 개별구현한다.
-
PercentPolicy
-
NonePolicy
-
method2-2: 템플릿policy를 일반class + 전략policy로 변환(2개의 전략객체를 사용하는 일반policy)
설명
-
현재 전략condition을 머금은
템플릿policy(확장시 조합폭발)
를 확장가능성을 고려한 차악일반policy클래스 + 전략action(의존성폭발)
로 변경한다
실습
-
템플릿메소드패턴의 추상클래스 DiscountPolicy를 -> 일반클래스로 바꾼다.
- abstract제거 & 훅메서드 정의 제거
- 템플릿메소드내 훅메서드(내수용메서드)앞에 전략객체(전략메서드+ -er)
소문자로 달아서
훅메서드 -> 전략객체.전략메서드()로 변경하여 개별구현시키기 -
전략객체를 필드로 생성후 생성자 주입
- 현재 전략condition을 머금고 있기 때문에, 전략객체 2개를 사용하는 일반클래스가 된다.
- 전략condition은 생성자 주입이 아니라, 빈컬렉션 -> 여러개+유연하게 setter(add)로 처리하는 중이다.
-
전략 인터페이스 및 오페레이터 완성
- 전략이 들어가는 순간 strategy패키지로 파서 넣어주자.
-
템플릿메소드패턴의 구상체들을 전략객체로 변경한다. 구조가 유사하므로 조금만 바꿔준다.
-
클래스명을
구상내용
+전략인터페이스명
으로 변경 -
상속을 impl로 변경
- 상속관련 super() 등 삭제
-
protected 훅메서드를 public 전략메서드로 접근제한자 변경
-
훅메서드명을 전략메서드로 변경
- 메서드명 변경이나 삭제시 f2/alt+del 이용해서 변경/삭제할 것
-
나머지 템플릿 구상체들도 전략객체로 바꿔준다.
-
-
Main이나 Test에서는 전략객체를 생성하고, 일반클래스 DiscountPolicy에 생성자 주입하도록 변경해서 사용한다.
method2-3: policy전략객체마다 위임&캐싱된 policy전략Factory 생성
설명
- 생성 <-> 사용을 분리한다.
- 생성해주는 Factory를 만든다.
- Factory별 캐싱을 적용해서, 전략객체별-Factory객체 -> 전략객체별 한번만 만든다.
- 생성해주는 Factory를 만든다.
- 생성(전략객체 생성)해주는 Factory가 사용(전략객체로 전략메서드 호출)의 책임까지 위임받는다.
- 전략인터페이스 구현 -> 전략메서드 정의시 내부에서 생성->사용까지
실습
-
전략인터페이스를 구현한
위임된 Factory
를 생성하고, 정책적용객체(전략객체 주입)의 변수명을전략객체 -> factory
로 변경한다.- 위임된 팩토리는
전략객체별로 생성
하며, 전략객체를 미리 생성 -> 강제 주입하는 대신전략객체 대신 factory로 주입
하고 factory가 내부에서 전략객체를 필요시마다 캐싱하여 1회만 생성하며, 사용될때 생성을 한다.- 전략인터페이스 구현한 Factory 생성
- 기존 전략객체명 복사해놓은 상태 + Factory만 붙이기
- 정책적용 객체는
기존에는 미리 생성된 전략객체를 강제 주입
->전략객체 대신 factory를 주입할 예정
- 전략인터페이스 구현한 Factory 생성
- 위임된 팩토리는
-
Factory가 구현해야할 전략메서드 내부에서,
내수용 & synchronized 캐싱 전략객체 생성메서드를 정의
한 뒤, 전략메서드를 사용한다.- 전략메서드 내부에서,
전략객체 생성 메서드create() or get전략객체
(내수용 +synchronized
)를 작성하되, 내부에서 캐싱 적용- 빈 cache필드를 이용하여 없으면 재할당해서 채운다. 있으면 그대로 반환한다.
- 전략메서드 내부에서,
-
정책적용 객체(DiscountPolicy)에 전략객체가 아닌 전략Factory를 주입시키도록 기존코드를 변경한다.