강의) 네오 3단계 블랙잭 피드백(4/4)
블랙잭 시작과 상태 패턴에 강의4
📜 제목으로 보기
- 추상화레벨 맞추기는 나중에
- 중요) 클라이언트 관점에서 더 필요한 기능이 남았는지 꼭데기 인터페이스에서 고민하기
- 중요) 특정클래스(추상클래스, 중카)에 속하는지 확인하기 위해 개별객체. isInstanceof 클래스.class 대신 -> 객체.is특정추클? 특정클래스는 true/ 나머지클래스는 false를 반환하는 && is특정클래스()의 이름을 딴boolean확인메서드를 새 메서드로서 추메/전메에 올려서 구현한다.
- 55) isInstanceof(중카.class) 안쓰고 매번 끝난 상태(중카, 추상클래스)인지 아닌지 확인하는 기능 -> 해당(끝난상태) 중카true vs 나머지 중카false를 반환하는 [확인클래스이름을 딴 boolean확인메서드]를 상카에 추가하기
- 중요) instanceof를 썼다면, 잘못된 설계다? -> 메서드에 메세지보내서 t/나머지f를 받을 수 있게 메서드로 관리하자.
- 56) 특정추클이 맞는지 확인메서드이지만, 모든 상태 객체가 대상이다 -> 새 메서드는 일단 추메/전메에 올려서 먼저 개발
- 중요) 개별구현이 예상되면(t/f확인메서드) -> 개별구현되는 곳까지 중간에 추클들은 무시하고 내려가서 구현해야한다. 중간/추클에 구현 impl == 중복코드 제거용으로 다시 추상메서드를 정의하지말고 무시하면 -> 자식들이 화내면서 개별구현해야한다 -> 즉, 개별구현해야된다면, 중간추클을 만나더라도 추상메서드 줄 필요없이 무시하면 개별구현자식들에게 자동전과되서 빨간줄 띄운다
- 암기) 상카 인터페이스에서 추메/전메로 올려서 개발시작하되, 개별구현되는 곳까지는 중카-추클을 무시해서 개별구현 전과를 돌려도 된다 -> 중간에 있다고 해서 미구현 추상메서드로 구현해 둘 필요없다
- 57) isXXXX() 대상 중카/추클까지 내려가서 개별구현으로서 true를 반환해준다
- 깜빡!) 중복제거를 위해 상카-추메/전메 -> 중카/추클에서 먹어서 정의하러 왔으면, 중카/추클 정의시는 항상 final로 자식 딴짓 못하게 막기
- 58) isFinished() 개별구현 책임이 전과된 isFinished 중카추클에 속하지 않은 중카추클이 아닌 개별구현체들 -> 중복코드제거 해줄 추클이 위에 없다면, 전과받은 개별구현체들이 모두 직접 구현
- 중요) 또 상태패턴의 상카 인터페이스에서 빠진 기능이 없는지 확인한다 블랙잭 라이브러리를 받아와서 이 기능들로 다 구현가능한지를 생각해보면 된다.
- 초대박) isinstanceof 특정 중카(추클)을 대신하는 boolean확인메서드가 아니라 개별 구현체마다 확인이 필요하다면, boolean확인메서드가 구현체 종류마다 필요해지고, 나머지는 모두 예외처리?해야만 한다 -> 개별구현체마다 다른 로직을 가지고 있으면서 && 굳이 (종료상태냐?) 확인할 필요없다면 : 추메/전메 -> [중카무시의 개별구현 책임전과]를 통해 [구현체마다 다른 로직을 구현]해서 다형성에서 알아서 처리되도록 구현하자
- 암기) 같은 카테고린데, 개별구현해야한다면? isInstanceof (x) -> is특정구현체? (x,그룹일경우만) -> 묻지말고 전략메서드처럼 추메/전메로 개별구현해서 알아서 작동하도록
- my) 전체가 크게 나뉘는 (종료상태들<->진행상태들 등)그룹에 대한 확인이면서 && isintanceof인지 꼭 물어봐야한다? isBoolean메서드를 추메/전메 올려서 개별구현까지 가서 구현
- my) 모든 구현체마다 다르게 구현되고 && 물어보면서 그에 따른 로직이 정해져있다? -> 공통메서드 로 추메/전메에 올리고 -> 물어보지말고 구현체들마다 직접 개별구현 시키자
- my+깨닮음) 어떤 것을 할 때마다, 해당 상태(객채)인지 물어보고 + 거기에 맞는 로직까지 정해져있다 -> 근데 그 상태가 제한된 종류로서 묶인다? -> 상카-구현체들로서 안물어보고 추메/전메로 전략패턴처럼 만들어주면 -> 구현체마다 알아서 작동하도록 개별구현해놓으면 -> if instanceof가 사라진다.
- 중요) 상태패턴에서 state구현체들은, 다음state의 판단을 위해 상태값에 정보를 가져야만한다. -> 정보를 상태값으로 가졌다면, 계산로직도 거기(state 구현체, 상태객체들)에서 구현(다르다변 추메/전메 -> 개별구현) 되어야한다.
- 59) state의 구현체들이 정보인 cards를 상태값도 가지고 있으니, 계산로직도 여기서 처리해야한다. 계산: 대상은 Finished된 state들만 대상이 되며, 계산(기본 정보로 계산) 중 <외부 입력을 받아 + 정보바탕으로 계산>: input으로 들어온 betMoney(double)을 [구현체별 다르게 계산 로직 구현]하여 -> 새로운 계산값을 output 응답하는 계산이 있다.
- my) 정보를 통한 계산이 아니라, 외부 금액input 등 정보를 가진 곳에서 계산로직을 가질 때, 외부재료를 input으로 받아서 -> 가진 상태객체의 정보cards를 바탕으로 -> 새 재료?로 return응답 해주는 계산로직도 생각하자. + 계산로직은 State패턴의 구현체객체들 중 finished에 해당한 애들만 계산로직을 가질 수 있다.
- 60) 외부재료받아 계산하는 로직의 [구현체마다 다르게 개별 구현] (finished 아래 구현체들만)
- 61) 개별 구현체 상태에서의 계산이… 추가 정보가 필요한 상태 -> 임의로 input 그대로 응답해놓는 버릇을 들여보자.
- 62) 추가 처리가 필요한 예외상황 -> 바깥에서 처리하기로 하고, 도메인내 자신의 역할만 생각해서 완성한다
- 63) hit와 ready는 profit계산자체가 불가 -> input있는 계산함수라도 개별구현시 예외처리
- 대박) 개별구현 하다가 중복코드가 보인다? 무시했던 추클에서 impl -> 후 중복부분만 구현(중클/추카 구현 메서드면 final) && 개별구현체마다 다른 부분 = 개별class들이 아는 부분 -> abstract메서드로 빼서 내려주기
- 중요) 중카/추클이 무시하고 내려보내 -> 개별 구현된 메서드들 중에서 상수 or 일부분만 중복이어도 -> 중카/추클에서 중복제거용impl 구현시행 &&상수(일부분)만 다시 abstract로 내려보내주기
- 중요+암기) 개별구현 전과시키려고 [impl구현 무시한 중카/추클 내]에서 새로운 중복 발견인 경우, impl구현 무시한 곳 -> impl시행하여 아래부분 중복제거를 시행하며 -> 상수든 뭐든 구현체별로 달라지는 부분은 상수라도 -> 메서드응답으로 빼고 -> abstract 메서드로 정의해서 자식들에게 [응답메서드로 상수(일부분) 개별구현]으로 내려주기
- 64) Finished내부, 상수만 구현체별로 다르고 메서드가 중복된다면? -> 제한된 중카/추클로만 올린 뒤, 달라지는 부분만 메서드로 추출하여 응답받도록 한 뒤 -> abstract메서드로 내려보내서 자식들이 상수응답하도록 하기
- 중요) 중카/추클은 상카 존재 시 개별구현 -> 무시하고 내려보내기 or 중복제거 -> final로 막아두고 구현 or 중카/추클 자식들의 중복시 -> 자신이 추메/전메처럼 abstract로 정의해서 뿌려준다. + 상수도 응답 메서드로서 뺀 뒤 -> protected? abstract로 정의하여, 추메/전메처럼 내려준다
- 중복제거 등, 추상화/상속 관련작업이 끝날 때마다, diagram을 보자
- 참고) 중카/추클(부모클래스)의 usage(extends)를 확인해보면, 같은 레벨의 자식들만 볼 수 도 있어서 -> 레벨이 맞는지 확인할 수 있다
- 65) 2개 남은 쌩구현체들에 대해, 공통메서드 확인후 중카/추클 추가해서 묶어주기
- 66) 반대편 추클과 동일한 레벨의 추상화(중카/추클) 만든 후, 기존에 개별구현들은 무시하여 자식들에게 전과된 체 두고 + 중복제거용 메서드들만 뽑아서 impl하여 final -> 자식들의 중복코드 제거한다
- 67) 추가 중카/추클은 기존 개별구현 메서드들을 제외시키면서 && 중복처리를 해줄 메서드들을 -> [implement Methods...] ->상카의 추메/전메들 중 선택해서 처리한다.
- 중요) 중복처리하는 중카/추클의 중복처리 메서드는 final로 자식딴짓못하게 막아야하며, final을 달아줬다면 -> 자식들이 extends 추가한 중카/추클하도록 넘어가자
- 68) 추클상 정의하는 메서드들은 무조건 접근제한자 확인할 것! 추클상 중복처리한다면, 자식에선 딴짓 못하게 final도 함께!!
- 69) final 중복처리 메서드로 중복처리까지 끝냈다면 -> 새로운 자식들에게 가서 자식들이 extends && 기존 중복코드들 제거해주기
- 중요+암기) 추상클래스에서 중복처리시 final을 달아서 처리해주면 -> 기존 개별구현하던 자식들이 extends한 순간부터 딴짓했다고 빨간줄내면서지워달라고 해준다.
- 70) 최종 다이어그램 확인하기
- 중요) 추상클래스에서 전메/추메의 abstract가 나온다면, protected로서 자식들이 개별구현하도록 풀어준다. ex> final 중복처리 메서드 내부에서 상수만 개별구현
- 중요) 상태패턴 최종 기능파악 + 인터페이스로 약속만 정의 -> 바깥에서 인페 추상체 state를 상태값으로 가진다면, 내부 구현 정보를 모르고 사용만 한다. (인페 추상체는 밖에서 주입해도 되고, 내부에서 즈그들끼리 변해도 되고.. 모른다) <-> state를 추클로 정의하면, 바깥에서 내부 정의를 다안다.?
- 인페로 정의한 State는 사용자가 내용은 모른체, 원하는 대로 사용할 수 있다.
- 71) Player가 인터페이스 객체(추상체)의 state를 상태값으로 가지는 순간, 그 내부 구현은 모르게 된다.
- 중요) 상태객체가 단독 public으로 열린 최초시작상태Ready 객체가 있다면, 시작이 그것 밖에 없으니, 생성자가 아니더라도 필드에서 바로 new Ready(); = (최초시작상태 객체)로 초기화`해줘도 된다.
- 72) 상태사용자 Player 등은, 상태업데이트 메서드 state.draw(card)를 사용하는 메서드를 한번더 만들어줘야한다( 객체를 포장하는 조합처럼). + 이 때, 필요한 재료(card)를 바로 줄지, 아니면 더 바깥상태의 재료를 받아서 내부에서 꺼내서서 넘길지(Deck.pick() -> card)는 사용자 맘이다. -> 어떻게 되었든 Player는 인터페이스로 연결된 State를 모른다.
- 73) 사용자 가 끝나기전 호출가능 메서드들(draw, stay)을 호출하는 메서드를 작성할 때는, 항상 내부에서 현재State가 아직 안 끝난 상태인지 확인후 호출되도록 해야한다.
- 74) state사용자가 상태변화메서드draw()의 재료뭉태기를 파라미터로 + while + is끝난상태객체 될대까지로 돌리면 한번에 계속 호출할 수 도 있다.
- my) 매번 끝났는지 확인가능 + 끝날때까지 재료가 매번 제공되면 -> if로 1동작만 할 것을 -> while로 여러동작할 수 있다.
- 남은일
추상화레벨 맞추기는 나중에
클라이언트 관점에서 더 필요한 기능
이 남았는지 꼭데기 인터페이스에서 고민
하기
중요)
메서드]들 고민
해보기
중요) 기존 [상태패턴용 인페
(인자->파라미터로 오는) 추가정보가 있냐/없냐
에 따라 -> 추가정보을 유발된 상태값 업데이트냐/ 원래 상태값의 조회해서 처리냐
를 구분 + (2) 응답값
을 통해 추상체 or 객체냐/상태값/값이냐
-> 처리내용이 같은 상카아래의 구현체 중 1개 객체 생성이냐/ 내부값 단순 조회/ 연산
이냐가 나눠진다.
my+ 깨닮음 ) 메서드는 (1)public interface State {
State draw(final Card card);
// [추가 정보]를 받아서 [상태값을 업데이트해서 -> 새 객체를 만들어내겠군]
// 응답이 추상체(인터페이스)? -> 서로 다른 구현체로 바뀔 수도 있겠군
// 구현체끼리 바뀌려면 -> 같은 상태값 && 상태값을 재료로 받는 생성자가 있어야겠지
State stay();
// 추가 정보가 없는 메서드? 상태값을 업데이트보단 [조회해서 처리] 확률이 높겠다.
// -> 아무래도 [현재 상태값을 조회하여 -> 무엇인가 처리]할텐데,
// -> 응답값 [추상체다? ] -> [조회해서 다른 구현체 객체]로도 갈 수 있을 듯?
Cards cards();
// 추가 정보가 없는 메서드? 상태값을 업데이트보단 [조회해서 처리] 화률이 높겠다.
// -> 아무래도 [현재 상태값을 조회하여 -> 무엇인가 처리]할텐데,
// -> 응답값이
}
54) 상태패턴 상카에서 빠진 기능 살펴보기
public interface State {
State draw(final Card card);
State stay();
Cards cards();
}
현재 상태 종류 (1) 끝난 상태 3개 (2) 최초시작&&진행가능 상태 1개 (3) 중간 진행가능상태 (1)
상태 상카의 현재기능 (1)상태변화 트리거(draw(추정)) + (2) (자의)종료상태 만들기(stay) + (3)현재상태 상태값getter(cards) - (중복제거으로 올렸더니 자식들 개별구현시 상태값 뽑아쓰기용)
끝났느지 안끝났는지 확인하는 기능은 필수
로 제공되어야한다.
3개 기능 이외에 더 필요한 기능은? (4) 매번
객체.is특정추클? 특정클래스는 true/ 나머지클래스는 false를 반환하는 && is특정클래스()의 이름을 딴boolean확인메서드
를 새 메서드로서 추메/전메에 올려서 구현
한다.
중요) 특정클래스(추상클래스, 중카)에 속하는지 확인하기 위해 개별객체. isInstanceof 클래스.class 대신 ->
매번 끝난 상태(중카, 추상클래스)인지 아닌지 확인하는 기능
-> 해당(끝난상태) 중카true vs 나머지 중카false를 반환하는 [확인클래스이름을 딴 boolean확인메서드]를 상카에 추가
하기
55) isInstanceof(중카.class) 안쓰고 까먹) Finished처럼, 중카/추클 전체에 적용되는 메서드들은, 자식들이 딴짓 못하게 final로 막아주기
중요) instanceof를 썼다면, 잘못된 설계다? -> 메서드에 메세지보내서 t/나머지f를 받을 수 있게 메서드로 관리하자.
특정추클
이 맞는지 확인메서드
이지만, 모든 상태 객체가 대상이다 -> 새 메서드는 일단 추메/전메에 올려서 먼저 개발
56)
인페 안에서 접근제한자 생략 -> 자동public
이므로 returnType + 파라미터의 시그니처
만 정의한다.
상카인페에 새 추메/전메를 올릴 때 public interface State {
State draw(final Card card);
State stay();
Cards cards();
// 하위 특정클래스 확인후 t/f를 반환해줄 메서드 추가
boolean isFinished();
}
중간에 추클들은 무시하고 내려가
서 구현해야한다. 중간/추클에 구현 impl == 중복코드 제거용으로 다시 추상메서드를 정의하지말고 무시하면 -> 자식들이 화내면서 개별구현해야한다
-> 즉, 개별구현해야된다면, 중간추클을 만나더라도 추상메서드 줄 필요없이 무시하면 개별구현자식들에게 자동전과되서 빨간줄 띄운다
중요) 개별구현이 예상되면(t/f확인메서드) -> 개별구현되는 곳까지
Finished
<-> 그외 중카
의 개별구현이 예상되면, 개별구현되는 상위 중카추클까지 내려가서 구현
한다. (최상위 중카를 무시하고 내려가면, 자식들에게 전과되어 개별구현하게 한다)
최상위 중카인 Started가 있지만,
개별구현되는 곳까지는 중카-추클을 무시해서 개별구현 전과를 돌려도 된다
-> 중간에 있다고 해서 미구현 추상메서드로 구현해 둘 필요없다
암기) 상카 인터페이스에서 추메/전메로 올려서 개발시작하되, 57) isXXXX() 대상 중카/추클까지 내려가서 개별구현으로서 true를 반환해준다
-
상카인
State
에서 추메/전메로 올려서 시작했으면서 && 중카인Started
를 건너띄었다면?-
(추가 중카인 Finished 역시 필수 구현체X & 중복코드라도 아직은 구현안해준 상태)에서
**
중카 추클이 구현impl을 무시했다면, 개별구현 책임이 자식들한테 넘어가 화가나있다
**
-
-
일단 isFinished()의 true를 대답해줄 그룹에 대해서
추클에 중복코드로서 구현
해준다.
중복제거를 위해
상카-추메/전메 -> 중카/추클에서 먹어서 정의
하러 왔으면, 중카/추클 정의시는 항상 final로 자식 딴짓 못하게 막
기
깜빡!) - 아래 일부사진들을 보면 중복제거용 부모 먹어주는 코드인
isFinished
가 final이 안달려있다.
isFinished 중카추클에 속하지 않은
중카추클이 아닌 개별구현체들
-> 중복코드제거 해줄 추클이 위에 없다면, 전과받은 개별구현체들이 모두 직접 구현
58) isFinished() 개별구현 책임이 전과된 -
현재 isFinished가 아닌 Ready와 Hit에 불이 나있다.
-
Ready
-
전과된 직접 개별구현 -> 끝난상태냐? false
-
-
Hit 역시 마찬가지 -> 끝난상태냐? false
-
상태패턴의 상카 인터페이스
에서 빠진 기능이 없는지 확인
한다 블랙잭 라이브러리
를 받아와서 이 기능들로 다 구현가능한지
를 생각해보면 된다.
중요) 또 - 상태변화 유발 메서드 with 파라미터(추가정보) -> draw(card)
- 자의로 끝난상태로 종료시키기 -> stay
- 구현체에서 부모상태값정보 받아먹기용 getter -> cards
- 현재 끝난 상태인지 확인 -> isFinished
- ???
계산로직도 상태 상카의 추메/전메
로 추가해준다.
중요) 상태패턴의 상태객체가 cards정보를 가지고 있으니 -> 필수 기능외에 public interface State {
State draw(final Card card);
State stay();
Cards cards();
boolean isFinished();
}
구현체(상태객체) 종류마다 [isinstanceof 대신 boolean확인메서드]가 필요해지는데???
중요) 계산profit() 하려면, 상태객체마다. isBust()인지 / isBlackjack() / isStay() 인지
개별 구현체마다 확인이 필요하다면, boolean확인메서드가 구현체 종류마다 필요해지고, 나머지는 모두 예외처리?
해야만 한다 -> 개별구현체마다 다른 로직을 가지고 있으면서 && 굳이 (종료상태냐?) 확인할 필요없다면 : 추메/전메 -> [중카무시의 개별구현 책임전과]를 통해 [구현체마다 다른 로직을 구현]해서 다형성에서 알아서 처리되도록 구현
하자
초대박) isinstanceof 특정 중카(추클)을 대신하는 boolean확인메서드가 아니라 암기) 같은 카테고린데, 개별구현해야한다면? isInstanceof (x) -> is특정구현체? (x,그룹일경우만) -> 묻지말고 전략메서드처럼 추메/전메로 개별구현해서 알아서 작동하도록
전체가 크게 나뉘는 (종료상태들<->진행상태들 등)그룹에 대한 확인
이면서 && isintanceof인지 꼭 물어봐야
한다? isBoolean메서드를 추메/전메 올려서 개별구현까지 가서 구현
my)
모든 구현체마다 다르게 구현
되고 && 물어보면서 그에 따른 로직이 정해져있다?
-> 공통메서드 로 추메/전메에 올리고 -> 물어보지말고 구현체들마다 직접 개별구현
시키자
my)
해당 상태(객채)인지 물어보고 + 거기에 맞는 로직까지 정해져있다
-> 근데 그 상태가 제한된 종류로서 묶인다?
-> 상카-구현체들
로서 안물어보고 추메/전메로 전략패턴처럼 만들어주면 -> 구현체마다 알아서 작동하도록 개별구현
해놓으면 -> if instanceof가 사라진다.
my+깨닮음) 어떤 것을 할 때마다,
다음state의 판단을 위해 상태값에 정보를 가져야만
한다. -> 정보를 상태값으로 가졌다면, 계산로직도 거기(state 구현체, 상태객체들)에서 구현(다르다변 추메/전메 -> 개별구현)
되어야한다.
중요) 상태패턴에서 state구현체들은,
계산: 대상은 Finished된 state들만 대상
이 되며, 계산(기본 정보로 계산) 중 <외부 입력을 받아 + 정보바탕으로 계산>: input으로 들어온 betMoney(double)을 [구현체별 다르게 계산 로직 구현]하여 -> 새로운 계산값을 output 응답
하는 계산이 있다.
59) state의 구현체들이 정보인 cards를 상태값도 가지고 있으니, 계산로직도 여기서 처리해야한다.
정보를 가진 곳에서 계산로직
을 가질 때, 외부재료를 input으로 받아서 -> 가진 상태객체의 정보cards를 바탕으로 -> 새 재료?로 return응답 해주는 계산
로직도 생각하자. + 계산로직은 State패턴의 구현체객체들 중 finished에 해당한 애들만 계산로직을 가질 수 있다.
my) 정보를 통한 계산이 아니라, 외부 금액input 등 -
상태에 따라,
외부input인 배팅금액
을 받아 ->상태마다 개별적으로 다르게 계산
해서새로운 배팅금액을 output으로 응답
한다.- 이 때, Finished아래의 구현체들만
결과
계산 로직을 가진다.
- 이 때, Finished아래의 구현체들만
그 외부재료에 계산한 값을 돌려주는 경우가 있다는 것을 생각
my) 계산시 외부재료가 필요한 경우도 있다. 참고) 돈 계산의 원시형은 일단 double로 받아서 double로 내어주자
public interface State {
State draw(final Card card);
State stay();
Cards cards();
boolean isFinished();
double profit(double money); // 계산 중에 외부에서 받은 것을 계산해서 응답해준다.
}
60) 외부재료받아 계산하는 로직의 [구현체마다 다르게 개별 구현] (finished 아래 구현체들만)
-
blackjack ->
외부재료(input money)를 * 2
하는 계산후 응답해준다.-
개별구현을 위해 중카/추클에서 impl무시하면, 자식들이 불나있다.
public final class Blackjack extends Finished { Blackjack(final Cards cards) { super(cards); } @Override public double profit(final double money) { return money * 1.5; } }
-
-
bust : 외부입력만큼, 손해로 작용한다면
* -1
을 해주면 된다.public final class Bust extends Finished { Bust(final Cards cards) { super(cards); } @Override public double profit(final double money) { return money * -1; } }
추가 정보가 필요한 상태 -> 임의로 input 그대로 응답해놓는 버릇
을 들여보자.
61) 개별 구현체 상태에서의 계산이… -
stay
상태에서는추가정보로서 딜러의 cards와 비교
를 해야한다. ->일단 무시하고 원본을 돌려놓는다.
public final class Stay extends Finished { Stay(final Cards cards) { super(cards); } @Override public double profit(final double money) { return money; } }
도메인내 자신의 역할만 생각해서 완성
한다
62) 추가 처리가 필요한 예외상황 -> 바깥에서 처리하기로 하고, 참고) 상호작용의 검증/조건이 있더라도, 개별 도메인 작성시에는 자기역할만 순수하게 완성한다.
- 현재 state가 blackjack 일때? 상대도 blackjack?
- 체스로 치면 king이 움직이는 것?
- 앞에 기물이 있는 예외상황은 바깥(board)에서 처리하고 일단 king자신 이 갈 수 있는 조건으로 계산한다.
- 상대방도 blackjack이면, 이익은 0배로 무승부인데?,
일단 내가 blacjakc일때의 상금 1.5배만 생각해서 완성
한다
- 체스로 치면 king이 움직이는 것?
63) hit와 ready는 profit계산자체가 불가 -> input있는 계산함수라도 개별구현시 예외처리
@Override
public double profit(final double money) {
throw new IllegalStateException();
}
무시했던 추클에서 impl
-> 후 중복부분만 구현(중클/추카 구현 메서드면 final)
&& 개별구현체마다 다른 부분 = 개별class들이 아는 부분 -> abstract메서드로 빼서 내려주기
대박) 개별구현 하다가 중복코드가 보인다?
중카/추클이 무시하고 내려보내 -> 개별 구현된 메서드들
중에서 상수 or 일부분만 중복이어도 -> 중카/추클에서 중복제거용impl 구현시행 &&상수(일부분)만 다시 abstract로 내려보내주기
중요)
개별구현 전과시키려고 [impl구현 무시한 중카/추클 내]에서 새로운 중복 발견
인 경우, impl구현 무시한 곳 -> impl시행하여 아래부분 중복제거
를 시행하며 -> 상수든 뭐든 구현체별로 달라지는 부분
은 상수라도 -> 메서드응답으로 빼고 -> abstract 메서드로 정의해서 자식들에게 [응답메서드로 상수(일부분) 개별구현]으로 내려주기
중요+암기)
메서드로 추출하여 응답
받도록 한 뒤 -> abstract메서드로 내려보내서 자식들이 상수응답
하도록 하기
64) Finished내부, 상수만 구현체별로 다르고 메서드가 중복된다면? -> 제한된 중카/추클로만 올린 뒤, 달라지는 부분만 -
Finished에서
무시했던 노필수 impl구현
을 해줘서, 중복제거용 코드로 먹어준다.
상카 존재
시 개별구현 -> 무시하고 내려보내기
or 중복제거 -> final로 막아두고 구현
or 중카/추클 자식들의 중복시 -> 자신이 추메/전메처럼 abstract로 정의해서 뿌려준다.
+ 상수도 응답 메서드로서 뺀 뒤 -> protected? abstract로 정의하여, 추메/전메처럼 내려준다
중요) 중카/추클은 -
**개별 클래스들이 알고 있는 부분(메서드 구현 뿐만 아니라
상수
도!!)은개별 클래스(구현체)들이 응답해줄 abstract메서드로 뺀다
**- 상수를 메서드로 뺄 때,
상수이름을 메서드로 네이밍()
해주는 센스
-
중카/추클에 정의하는데 final로 중복구현 vs
개별구현의 최상위라면, 중복코드는 final로 정의해주되, 내부에 개별구현 코드가 보인다면, 메서드로 뺀 뒤 -> 추메/전메처럼 뿌려주려면, abstract 메서드로 내려주기
-
개별구현시키려고
abstract메서드
로 뽑았더니,자식들 구현하라고 protected
로 찍혀있다. -
abstract로 추메/전메처럼 개별구현으로 내려보내면 -> 자식들 불 들어온다.
- 상수를 메서드로 뺄 때,
중복제거 코드내
라도 가능하며, 상수, 일부분이라도 (1) 메서드로 빼고
-> (2)abstract로 내려준다
.
암기) 중카-추클이 개별구현을 내려줘야한다면, -
개별 구현체들이 알고 있는 개별 상수들을 메서드로 구현해준다.
-
blackjack
-
올린 중복코드는 제거한다.
-
중복코드를 제외한
상수의 개별구현
을 abs -> impl해줘서 응답해준다.public final class Blackjack extends Finished { Blackjack(final Cards cards) { super(cards); } @Override protected double earningRate() { return 1.5; } }
-
-
나머지 들도, 중복코드를 삭제하고, 상수를 응답하는 개별구현 메서드를 구현한다
public final class Bust extends Finished { Bust(final Cards cards) { super(cards); } @Override protected double earningRate() { return -1; } }
-
stay: 원본 그대로 돌려주고 밖에서 나중에 예외처 계산함
public final class Stay extends Finished { Stay(final Cards cards) { super(cards); } @Override protected double earningRate() { return 1; } }
-
중복제거 등, 추상화/상속 관련작업이 끝날 때마다, diagram을 보자
-
profit()
중복코드로서 중카/추클에서 정의해줬다- 중복코드 -> 외부에서 호출할 놈 -> public
-
profit()
내에서 구현체별 달라지는 부분(상수)는 내부에서 메서드추출 ->추카/중클에서 (protected)abstract로 전메/추메처럼 개별구현으로 내려보낸다
-
earningRate()
는 개별구현체별 다르게 구현되는 상수를 추출한 메서드
-
중카/추클(부모클래스)의 usage(extends)
를 확인해보면, 같은 레벨의 자식들
만 볼 수 도 있어서 -> 레벨이 맞는지 확인
할 수 있다
참고) -
Started
의 추클에서usage(shift+F12)
를 통해, extends자식들이 어떤 것들이 있는지를 보고 레벨을 확인해보자.- 추클Finished
- 구현체Hit
- 구현체Ready
65) 2개 남은 쌩구현체들에 대해, 공통메서드 확인후 중카/추클 추가해서 묶어주기
중카/추클아래 구현체(자식들)은 본인의 역할만 잘하고 있는 것 같은데, hit와 ready는 좀 더러운 것 같다
-
blackjack
public final class Blackjack extends Finished { Blackjack(final Cards cards) { super(cards); } @Override protected double earningRate() { return 1.5; } }
쌩구현체들의 공통점 찾기
-
Hit
@Override public boolean isFinished() { return false; } @Override public double profit(final double money) { throw new IllegalStateException(); }
-
Ready
@Override public boolean isFinished() { return false; } @Override public double profit(final double money) { throw new IllegalStateException(); }
기존에 개별구현들은 무시하여 자식들에게 전과된 체 두고
+ 중복제거용 메서드들만 뽑아서 impl하여 final -> 자식들의 중복코드 제거
한다
66) 반대편 추클과 동일한 레벨의 추상화(중카/추클) 만든 후, -
Finished의 반대 Running(중카/추클)만들기
더 위의 중카/추클이, 상태값+생성자 (for getter?) 내려준다면
, super()로 내려주는 상태값 초기화는 기본적으로 해줘야함
중카/추클 생성하는데, -
Running
<-> Finishedpublic abstract class Running extends Started { protected Running(final Cards cards) { super(cards); } }
기존 개별구현 메서드들을 제외시키면서 && 중복처리를 해줄 메서드들
을 -> [implement Methods...] ->상카의 추메/전메들 중 선택
해서 처리한다.
67) 추가 중카/추클은 -
중간에 추가된 Finished대항마
Running
은 impl해서 중복들을 상카-추메/전메중에 확인해서 처리해야한다. -
isFinihsed는 피니쉬의 대항마 추상레이어로서 아래 똑같이 중복
return false
마찬가지로 profit도 아직 안끝났으면, 수익률계산불가 -> 예외처리를을 중복처리한다.
public abstract class Running extends Started { protected Running(final Cards cards) { super(cards); } @Override public boolean isFinished() { return false; } @Override public double profit(final double money) { throw new IllegalStateException(); } }
중카/추클의 중복처리 메서드는 final
로 자식딴짓못하게 막아야하며, final을 달아줬다면 -> 자식들이 extends 추가한 중카/추클
하도록 넘어가자
중요) 중복처리하는
추클상 중복처리한다면, 자식에선 딴짓 못하게 final도 함께!!
68) 추클상 정의하는 메서드들은 무조건 접근제한자 확인할 것!
public abstract class Running extends Started {
protected Running(final Cards cards) {
super(cards);
}
@Override
public final boolean isFinished() {
return false;
}
@Override
public final double profit(final double money) {
throw new IllegalStateException();
}
}
final 중복처리 메서드
로 중복처리까지 끝냈다면 -> 새로운 자식들에게 가서 자식들이 extends && 기존 중복코드들 제거
해주기
69) - Running
- Hit
- Stay
-
처리된 중복메서드만 삭제(
final로 막아놔서 -> extends한 자식은 @Override시 빨간줄
) -
Ready도 똑같이 처리한다.
중요+암기) 추상클래스에서 중복처리시 final을 달아서 처리해주면 -> 기존 개별구현하던 자식들이 extends한 순간부터 딴짓했다고 빨간줄내면서지워달라고 해준다.
70) 최종 다이어그램 확인하기
추상클래스에서 전메/추메의 abstract
가 나온다면, protected로서 자식들이 개별구현
하도록 풀어준다. ex> final 중복처리 메서드 내부에서 상수만 개별구현
중요) 중요) 상태패턴 최종 기능파악 + 인터페이스로 약속만 정의 -> 바깥에서 인페 추상체 state를 상태값으로 가진다면, 내부 구현 정보를 모르고 사용만 한다. (인페 추상체는 밖에서 주입해도 되고, 내부에서 즈그들끼리 변해도 되고.. 모른다) <-> state를 추클로 정의하면, 바깥에서 내부 정의를 다안다.?
public interface State {
State draw(final Card card);
State stay();
Cards cards();
boolean isFinished();
double profit(double money);
}
-
isFinished()
가 판단가능해서-
끝나지 않았으면, 추가정보로 계속 상태변화
draw( )
-
끝났으면, 그 상태에서 결과계산
profit( )
-
끝나지 않았으면, 추가정보로 계속 상태변화
-
stay()
로 주체(Player)가 원할 때, isFinished()에 걸리도록 끝내주고- 종료도.. 종료상태를 먼저 만들어주고, isFinished()에 걸려야하는 구나!
-
cards()
로 출력이나, 상태업데이트를 위해 현재상태를 가져온다
인페는 말그대로 인터페이스만 제공해주고, 내부구현은 모른다. -> 인터페이스로 연결되었다면, Player입장에서는 state 가 어떻게 동작하는지 1도 모른다. (내부동작을 모른다)
- 인터페이스는 바깥에서 사용할 때, 내부 구현을 모르는 상테로,
약속에만 맞게 동작하는구나
정도만 알 수 있다- Player ->
private State state;
로 상태값으로 가지긴 하지만, 인페 객체(추상체)를 갖다쓰는 순간 내부 구현고 직접 구현체가 들어갈 때만 거기에 맞게 작동하므로)
- Player ->
- 인터페이스가 좋다고 해도, 많아지면 장황해진다
- 추클과의 논쟁은 끝이 없다.
인페로 정의한 State는 사용자가 내용은 모른체, 원하는 대로 사용할 수 있다.
71) Player가 인터페이스 객체(추상체)의 state를 상태값으로 가지는 순간, 그 내부 구현은 모르게 된다.
-
state와는 다른
.player패키지
->Player
를 만들기 -
State의 사용처는
인페객체 = 추상체
를상태값
으로 가져, 내부구현은 모른다.
단독 public으로 열린 최초시작상태Ready 객체
가 있다면, 시작이 그것 밖에 없으니, 생성자가 아니더라도 필드에서 바로 new Ready(); = (최초시작상태 객체)
로 초기화`해줘도 된다.
중요) 상태객체가
열려있는 접근제어자는 Ready객체 밖에 없어서
private State state = new Ready();
로 시작
암기) 상태패턴은 필드에서부터 -
Ready로 시작할 수 밖에 없다면, 생성자에서 초기화 안하고 필드에서 해도 된다.
public class Player { private State state = new Ready(); }
필요한 재료(card)를 바로 줄지
, 아니면 더 바깥상태의 재료
를 받아서 내부에서 꺼내서서 넘길지(Deck.pick() -> card)
는 사용자 맘이다. -> 어떻게 되었든 Player는 인터페이스로 연결된 State를 모른다.
72) 상태사용자 Player 등은, 상태업데이트 메서드 state.draw(card)를 사용하는 메서드를 한번더 만들어줘야한다( 객체를 포장하는 조합처럼). + 이 때, public class Player {
private State state = new Ready();
// state사용 객체 입장에서, 재료 뭉태기를 한번에?
public void draw(Deck deck) {
state = state.draw(deck.pick());
}
//or 1개 재료만? -> 선택 가능함.
public void draw(Card card) {
state = state.draw(card);
}
}
끝나기전 호출가능 메서드들(draw, stay)을 호출
하는 메서드를 작성할 때는, 항상 내부에서 현재State가 아직 안 끝난 상태인지 확인후 호출
되도록 해야한다.
73) 사용자 가 public interface State {
State draw(final Card card);
State stay();
Cards cards();
boolean isFinished();
double profit(double money);
}
상태변화메서드draw()의 재료뭉태기
를 파라미터로 + while + is끝난상태객체 될대까지
로 돌리면 한번에 계속 호출할 수 도 있다.
74) state사용자가 public class Player {
private State state = new Ready();
public void draw(Deck deck) {
while (!state.isFinished()) {
state = state.draw(deck.pick());
}
}
}
매번 끝났는지 확인가능
+ 끝날때까지 재료가 매번 제공되면
-> if로 1동작만 할 것을 -> while로 여러동작할 수 있다.
my) -
메서드가 card를 파라미터로 받는다고 해서 외부에서 card를 직접꺼내주지말고,
외부에서는 card덩어리의 객체
를 파라미터로 받아보자-
Player
- draw <-
Deck
( = cards by .pick() )- if ! isFinished()
- state <- card <- Deck.pick()
-
while ! isFinished()
- state <- card <- Deck.pick()
- if ! isFinished()
- draw <-
card
- if ! isFinished()
- state <- card
- if ! isFinished()
public class Player { private State state = new Ready(); public void draw(Deck deck) { while (!state.isFinished()) { state = state.draw(deck.pick()); } } public void draw(Card card) { if (!state.isFinished()) { state = state.draw(card); } } }
- draw <-
-
남은일
- 상태패턴에서 stay일 때 profit구현(임시로 money 1배로 반환)