SIDE)추상체X추상체 관계에서 템플릿,전략패턴 적용
추상체x추상체의 if instanceof를 템플릿, 전략패턴 적용
📜 제목으로 보기
- 상호의존도 도시
- 문제점
- 실습용 초기코드
- 해결1: 추상체 X 추상체로 인해 한쪽 구상체가 넘어오는 추상체의 instanceof 구상형(제네릭)마다 다른 개별로직(자체 추상화) 구현을 해결해보기
- 해결2: if instanceof는 [전략패턴]으로 시킬 수 있음 시키자.
- 추가: 전략객체/템플릿구상체들의 개별구현로직을 외부로 밀도록 나 자신을 추상화
상호의존도 도시
문제점
- Director 내부에서 추상체
ProjectPaper
를 가지고 있지만, 추상층의 정보(전략메서드, 템플릿메서드
)가 부족하여, 특정형인지 확인후 작업한다.- instanceof는 2개이상이면 if의 문제라고 본다.
- 개별구상체를 물어보지말고 시킬 수 있는지 확인한다. (혹시나 this로 넘어가면… 문제가 생길 수 있다.)
- 중복로직이 존재하면, 템플릿메서드로
- 중복로직 없으면, 전략패턴으로
-
FrontEnd, BackEnd내부에서 추상체
ProjectPaper
를 받아오지만,추상층에 물어보고(get) -> 필드에 저장(set)
하기 위해서 if instacneof가 생긴 상태다.- 구상체별로 물어보지 않으려면 (getter -> setter)에서 set시키기 위해 this로 나 자신을 넘겨 시켜야 하는데
- 나 또한, Programmer의 구상체로서, 추상체로 넘어가 -> 물어보고 set시킨다.
-
나에게 set
등의 로직을 가져 나를 넘기면서 시켜야하는 로직일 때, 내가 추상체로 넘어갈 상황이면 넘기지 말고 물어보도록 두자. - instanceof가 2개이상이라 if의 문제라고 본다.
- 추상체에, 시켜서 해결하는 방법이 템플릿메서드, 전략메서드다. 하지만, 시키는 로직이 this(추상체)로 넘어갈 경우 따져야한다.
-
instanceof 2개이상이 해결이 안된다면
- 넘어온 추상체(paper)의 구상형들 자리에 제네릭 T를 넣어서 -> 인스턴스는 특정형을 사용할 수 있게 한다.
- if 2개이상으로 개별 구현로직이 생기기 때문에,
현재 class를 중간추상층 with T
로 만든 뒤,최종구상층에서 T를 개별구현
시키도록 한다.
실습용 초기코드
해결1: 추상체 X 추상체로 인해 한쪽 구상체가 넘어오는 추상체의 instanceof 구상형(제네릭)마다 다른 개별로직(자체 추상화) 구현을 해결해보기
설명
- 넘어오는 추상체에게 시킬 수 없다면(그 추상체(1)가 this(N, 나도추상체)로 받아가서 더 복잡해지는 1:N관계)
- 넘어오는 추상체에 전략메서드/템플릿메소드로 추상화로 시키기가 불가능 하다.
- 그렇다면, Type에 따른 개별구현 로직은
나를 추상화 + 개별구현메서드를 T형
으로 처리하는 수 밖에 없다. - 개별구현 로직이 구상층으로 넘어간다면, 나는 여러형을 T형으로 줘서, 최종구상층이 특정형을 알고 개별구현하게 한다.
-
내부에 instanceof = 여러Type
을 T의 제네릭으로 대체하려면, 나는-
인스턴스<특정형>의 일반class
이거나 -
T형에 따라 개별구현이 내부에 존재하는 구상체라면,
분신술 개별구현 익클<특정형>의 추상클래스
여야한다.
-
실습(템플릿 메소드 -> 제네릭)
-
제네릭으로 instanceof를 지우기 전에,
추상체 파라미터의 Type에 따른 개별구현 로직
을 제거하기 위해, 전략객체에 추상화가 아닌나를 추상화(중간추상층)화
해서if 1개를 없애야한다
- 각각의 if후
return createFrontEndProgram();
의 공통로직이 존재하므로템플릿메소드패턴
으로나를 추상클래스로 만들어 추상화
해야한다.-
여러 if들을 포함하는 전체로직이
public 템플릿메소드에 전체로직이 쌓여있는지 확인
한다. -> 현재 완료 -
1개의 if에 대해
전체로직 내부의 개별구현로직
은내수용메서드 형태의 protected abstract 훅메서드
로 추출한다 -
다른 if의 개별구현부는 주석처리후 if문을 삭제한다.
- 다른 if의 개별구현 로직들은 최종구상체들이 사용할 로직으로서 주석으로 보관하여 훅메서드 근처에 옮겨둔다.
- 클래스에는 abstract를 달아주고, 훅메서드는 protected abstract가 달려있는지 확인한다.
-
여러 if들을 포함하는 전체로직이
- 각각의 if후
-
1개의 if만 남기고 삭제하고(개별구현은 주석으로 챙겨놨다.) if 및 instanceof 삭제후 구상체 대신 추상체를 사용하도록 로직을 바꾼다.
-
이제 최종추상층(익클-분신술)이 개별구현시
특정형을 알고서 && 그것을 받아 개별구현
하도록제네릭T extends upperbound
처리를 해준다. -
이제 FrontEnd 인스턴스를 사용하던 곳에서
제네릭 + 익명클래스로 구현
해야한다.-
제네릭을 안달고 implements 훅메서드 하면, upperbound가 T자리를 차지하니 제네릭을 먼저 달고 구현한다.
-
개별구현은 T에 들어갈 구상체마다 다른데, 주석으로 보관해놨으니 참고한다.
-
익명클래스는, 분신술의 원조 추상클래스의 필드를 protected로 변경하여 편하게 사용
한다.
-
-
이제 추상체(paper) -> 추상체(programmer) 의
구상체(FrontEnd)이외에 나머지 구상체들(BackEnd)
도 똑같이추상화 -> 제네릭 처리
해준다. -
중간추상층이된 FrontEnd와 BackEnd가 각각이 템플릿메소드로서 공통로직을 가져 -> 상위추상층을 템플릿메소드패턴 적용해서 올리기
-
기존에
인터페이스
가 상위추상층으로 있으면, 훅메서드가 안올라가므로,추상클래스로 변경
먼저 해놓는다. -
compare file로 2개의 구상체를 띄워놓고, 구상체 1개를 선택하고
-
public 템플릿메서드 + private내수용 훅메서드를 만들고, 각각의 메서드명을 추상화해서 올린다.
-
private메서드를 같이 members로서 같이 들고 올라가야하므로 밑에 것을 선택한다.
-
훅메서드로 들고올라가는데, 이미 구현된 private메서드를 올리면, 자식은 부모를 개별구현된 상태로 남아있다
- 반면 올리기 전에도 훅메서드(protected abstract)였던 메서드와, public 템플릿 메서드는 그대로 올라가서, 자식에게는 업섹 된다.
-
-
-
-
-
메서드를 올리는 FrontEnd내 메서드가
T extends ProjectPaper
형을 써서 올리면, 상위추상층은 단지 upperBound로 구현하고 있으니최종구상층이 특정형이 아닌 추상체를 써라는 에러
가 나온다.-
FrontEnd
<T extends ProjectPaper>
의 부모인 extends Programmer에Programmer<사용 T>
를 쓰도록 만들고 -
Programmer class 자체에서는
<T extends ProjectPaper>
로 정의한다.- 사용 T를 미리 지정해놓고 -> 자동완성 ->
Change signature of to match <T>
를 사용하면 된다.
- 사용 T를 미리 지정해놓고 -> 자동완성 ->
-
이제 올라간 템플릿 메소드 및 훅메서드에서 추상형 대신 T형으로 정의해놓고, 최종구상층에서는 특정형을 알게 한다.
-
-
backEnd도 마찬가지 처리를 해준다.
- 제네릭이 제대로 되어있나 확인하고
- 템플릿메서드는 지워주고, 훅메서드는 메서드명을 맞춰준다.
-
이제 FrontEnd, BackEnd의 사용처(Director#runProjectPaper)로 가보면
-
자신들이 분신술로 인스턴스를 생성하면서, 특정형을 알면서 개별구현하도록 구현되어있다.
-
해결2: if instanceof는 [전략패턴]으로 시킬 수 있음 시키자.
설명
- if instanceof는 추상체에게 물어보고, 내 내부에서 펼치는 것 -> 추상체에게 getter이후의 로직까지 시킬 수 있나 확인한다.
- 현재 context도 같이 넘어가면
this
로 넘어가는데, this가 추상체인지 확인한다. 만약 추상체라면 N:1관계를 확인한다. - 지금은 추상체 -> 각 구상체 -> director(this)에 영향을 주는 로직이 없으므로 메서드(추상체)로 추출 -> 이동 -> 추상체.메서드()로 시킬 수 있다.
- 현재 context도 같이 넘어가면
- 공통로직이 충분히 있고, 틀이 잡히고, 나를 추상클래스로 + 훅 구상체class들(or익클분신술로 외부구현)을 만들거면
템플릿메소드패턴
으로 추상화 / 그게 아니라 들어오는 추상체를 전략인터페이스로 간주하고 전략객체들만 만들거면 if 내부 전체를 개별로직으로 보고전략패턴
으로 추상화- 현재는 public 메소드내에 있지만, 공통로직이 없다고 보면 된다.
deploy()는 director의 내수용 메서드이며, 추상체가 개입안하는 부분
이다. -
구상체들로부터 추상체를 만드는 게 아니라,
내부 if 로직으로 템플릿메소드 패턴을 적용한다면, 내 자신(Director)이 추상클래스
가 되어야하는데, Director를 추상클래스로 만든 이유가 없다. 들어오는 추상체에게 시키기만 하면 된다.- 템플릿메소드패턴의
추상클래스
+ 훅 구상체들 =전략객체주입 일반클래스
+ 전략인터페이스 + 구상 전략객체들- director내부 내용을 익클 분신술 director로 생성하면서 구현할만한 size가 아니다.
- 시킬 수 있으면 추상체에 시켜서 나를 추상화하면 안됨.
- 나 자신을 추상클래스로 -> ADirector BDirector등으로 만들것이 아니라면, 템플릿메소드패턴X
- 템플릿메소드패턴의
- 현재는 public 메소드내에 있지만, 공통로직이 없다고 보면 된다.
실습(전략 적용)
-
여러 if들을 포함하는 전체로직여러 if들내에구상체가 사용되어 반환되는 로직을 확인
한다.- 반환값이 2개이상이 되는 순간부터는 메서드 추출이 안되므로 반환값이 1개인 if가 있다면, 그쪽 if에서 메서드 추출한다.
- 구상체로부터 이어지는 로직과 원래 현재class의 로직을 구분해서 if별 개별구현 부분을 확인한 뒤 메서드로 추출한다.
-
1개의 if에 대해 전략메서드로 처리될
개별구현 로직만 내수용메서드( 구상체 )
형태로 추출한다. 전략객체가 될,현재 파라미터의 구상체class로 move하면 전략객체.전략메서드()
가 형태가 된다.-
1개의 전략메서드 내부 구현된 구상체class로 옮기기 위해서, 아직 추상체로 변수명을 바꾸진 않았다.
-
내부에 사용되는 구상paper의 내용이 있다면, this로 바뀐다.
-
-
추출한 예비전략메서드를 -> 선택된 구상체 내부로 로직을 이동
시킨다. -
옮겨간 구상체1개만의 전략메서드를
@Override를 통해 추상체(전략 인터페이스)에 오퍼레이터
로 만들어주고,해당 구상체if문을 추상체.전략메서드()
형태로 바꿔준다.
-
다른 if의 개별구현부는 주석처리
후나머지 if문을 삭제
한다- 다른 if의 개별구현 로직들은 최종구상체들이 사용할 로직으로서 주석으로 보관하여
훅메서드전략메서드 근처에 옮겨둔다.
- 다른 if의 개별구현 로직들은 최종구상체들이 사용할 로직으로서 주석으로 보관하여
-
주석처리한 개별구현로직은 각각의 전략객체에 구현될 메서드에 옮겨준다.
-
이 때, 반환값 갯수가 다를 경우, 배열을 응답값으로 활용한다.
- 추출한 전략메서드는 1개 Program, 2번째 전략객체의 응답값은 2개 Program -> 응답형을 배열로 바꿔서 처리해준다.
추가: 전략객체/템플릿구상체들의 개별구현로직을 외부로 밀도록 나 자신을 추상화
설명
- if분기에 해당하는 전략메서드 / 훅메서드들을 특정 구상체class가 담고 있다. 해당 개별구현을
나를 추상클래스로 추상화 -> 외부에서 익명클래스로 개별구현
한다면,최후에 개별구현 로직을 client에서 DI 선택해서 해결
가능한 형태를 만든다. -
나를 추상클래스화 해서, client에서 개별구현을 선택해서 작성하는 형태는,
개별구현로직이 달라질 때, 구상층 추가시 유용
할 수 가 있다. -
참고
실습(전략객체들의 중간추상층화 -> 전략메서드 구현을 client로)
-
개별구현하는 구상체들을 모두 abstract 달아주기
- 다는 순간, new 구상체();로 객체로 만들었떤 것들이 -> 단순 객체생성으로 사용 불가하게 됨.
- 다는 순간, 필수구현이 -> 선택구현으로서 익명클래스에서 구현해도 되도록 변경된다.
-
개별구현 로직을 복사한 뒤 -> 전략메서드 삭제 ->
생성자의 usage(alt + f7)
를 통해일반class의 객체로 생성되었던 곳(client)
에개별구현로직 복사해서 옮겨 구현
하기- 추상클래스로 변화 -> 단순 객체로 생성했던 곳이 익명클래스로 구현해야하는 것으로 바뀜 -> 생성자 사용처들에 개별구현로직 복사한 뒤 구현해주기
- 추상클래스상에 구현해서 막고 있는
전략메서드를 삭제해야 -> 구상체들 implement가 되니 구현로직만 객체생성처에 옮겨놓기
- 추상클래스상에 구현해서 막고 있는
- usage를 find Tool window로 보기 위해
alt + F7
을 활용한다.
- 옮긴 뒤 context(this)가 달라지는 것을 수정해준다.
- paper를 벗어난 상황이므로, paper의 필드를 얻으려면
this.필드 -> paper.getter()
로 변경해줘야한다.
- paper를 벗어난 상황이므로, paper의 필드를 얻으려면
- 추상클래스로 변화 -> 단순 객체로 생성했던 곳이 익명클래스로 구현해야하는 것으로 바뀜 -> 생성자 사용처들에 개별구현로직 복사한 뒤 구현해주기
-
나머지 전략객체(TxPackagePaper)도 추상화해주기
- abstract달기
- 생성자 사용처(객체 생성)에 가서 개별구현 로직 옮겨놓기
- 전략메서드 삭제후 생성자 사용처(객체 생성)에 익명클래스 구현하며 로직 만들기
-
참고