📜 제목으로 보기

추상화레벨 맞추기는 나중에

중요) 클라이언트 관점에서 더 필요한 기능이 남았는지 꼭데기 인터페이스에서 고민하기

중요) 기존 [상태패턴용 인페 메서드]들 고민해보기

image-20220323122456918

my+ 깨닮음 ) 메서드는 (1)(인자->파라미터로 오는) 추가정보가 있냐/없냐에 따라 -> 추가정보을 유발된 상태값 업데이트냐/ 원래 상태값의 조회해서 처리냐를 구분 + (2) 응답값을 통해 추상체 or 객체냐/상태값/값이냐 -> 처리내용이 같은 상카아래의 구현체 중 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)

image-20220324104540574

상태 상카의 현재기능 (1)상태변화 트리거(draw(추정)) + (2) (자의)종료상태 만들기(stay) + (3)현재상태 상태값getter(cards) - (중복제거으로 올렸더니 자식들 개별구현시 상태값 뽑아쓰기용)
3개 기능 이외에 더 필요한 기능은? (4) 매번 끝났느지 안끝났는지 확인하는 기능은 필수로 제공되어야한다.

중요) 특정클래스(추상클래스, 중카)에 속하는지 확인하기 위해 개별객체. isInstanceof 클래스.class 대신 -> 객체.is특정추클? 특정클래스는 true/ 나머지클래스는 false를 반환하는 && is특정클래스()의 이름을 딴boolean확인메서드새 메서드로서 추메/전메에 올려서 구현한다.

55) isInstanceof(중카.class) 안쓰고 매번 끝난 상태(중카, 추상클래스)인지 아닌지 확인하는 기능 -> 해당(끝난상태) 중카true vs 나머지 중카false를 반환하는 [확인클래스이름을 딴 boolean확인메서드]를 상카에 추가하기

image-20220324110056739

까먹) Finished처럼, 중카/추클 전체에 적용되는 메서드들은, 자식들이 딴짓 못하게 final로 막아주기

image-20220325092602060 image-20220325092707516

중요) instanceof를 썼다면, 잘못된 설계다? -> 메서드에 메세지보내서 t/나머지f를 받을 수 있게 메서드로 관리하자.

56) 특정추클이 맞는지 확인메서드이지만, 모든 상태 객체가 대상이다 -> 새 메서드는 일단 추메/전메에 올려서 먼저 개발

상카인페에 새 추메/전메를 올릴 때 인페 안에서 접근제한자 생략 -> 자동public 이므로 returnType + 파라미터의 시그니처만 정의한다.

image-20220324111327885

public interface State {
    State draw(final Card card);

    State stay();

    Cards cards();

    // 하위 특정클래스 확인후 t/f를 반환해줄 메서드 추가
    boolean isFinished();
}

중요) 개별구현이 예상되면(t/f확인메서드) -> 개별구현되는 곳까지 중간에 추클들은 무시하고 내려가서 구현해야한다. 중간/추클에 구현 impl == 중복코드 제거용으로 다시 추상메서드를 정의하지말고 무시하면 -> 자식들이 화내면서 개별구현해야한다 -> 즉, 개별구현해야된다면, 중간추클을 만나더라도 추상메서드 줄 필요없이 무시하면 개별구현자식들에게 자동전과되서 빨간줄 띄운다

최상위 중카인 Started가 있지만, Finished <-> 그외 중카의 개별구현이 예상되면, 개별구현되는 상위 중카추클까지 내려가서 구현한다. (최상위 중카를 무시하고 내려가면, 자식들에게 전과되어 개별구현하게 한다)

image-20220324112657561

암기) 상카 인터페이스에서 추메/전메로 올려서 개발시작하되, 개별구현되는 곳까지는 중카-추클을 무시해서 개별구현 전과를 돌려도 된다 -> 중간에 있다고 해서 미구현 추상메서드로 구현해 둘 필요없다

57) isXXXX() 대상 중카/추클까지 내려가서 개별구현으로서 true를 반환해준다

  1. 상카인 State에서 추메/전메로 올려서 시작했으면서 && 중카인 Started를 건너띄었다면?

    • (추가 중카인 Finished 역시 필수 구현체X & 중복코드라도 아직은 구현안해준 상태)에서

      **중카 추클이 구현impl을 무시했다면, 개별구현 책임이 자식들한테 넘어가 화가나있다 **

      image-20220324113025894

  2. 일단 isFinished()의 true를 대답해줄 그룹에 대해서 추클에 중복코드로서 구현해준다.

    image-20220324113117322 image-20220324113202372

깜빡!) 중복제거를 위해 상카-추메/전메 -> 중카/추클에서 먹어서 정의하러 왔으면, 중카/추클 정의시는 항상 final로 자식 딴짓 못하게 막

  • 아래 일부사진들을 보면 중복제거용 부모 먹어주는 코드인 isFinishedfinal이 안달려있다.

58) isFinished() 개별구현 책임이 전과된 isFinished 중카추클에 속하지 않은 중카추클이 아닌 개별구현체들 -> 중복코드제거 해줄 추클이 위에 없다면, 전과받은 개별구현체들이 모두 직접 구현

  • 현재 isFinished가 아닌 Ready와 Hit에 불이 나있다.

    image-20220324113345677

    image-20220324113356859

    • Ready

      • 전과된 직접 개별구현 -> 끝난상태냐? false

        image-20220324113450756 image-20220324113512463

    • Hit 역시 마찬가지 -> 끝난상태냐? false

      image-20220324113534925

중요) 또 상태패턴의 상카 인터페이스에서 빠진 기능이 없는지 확인한다 블랙잭 라이브러리를 받아와서 이 기능들로 다 구현가능한지를 생각해보면 된다.

  1. 상태변화 유발 메서드 with 파라미터(추가정보) -> draw(card)
  2. 자의로 끝난상태로 종료시키기 -> stay
  3. 구현체에서 부모상태값정보 받아먹기용 getter -> cards
  4. 현재 끝난 상태인지 확인 -> isFinished
  5. ???

중요) 상태패턴의 상태객체가 cards정보를 가지고 있으니 -> 필수 기능외에 계산로직도 상태 상카의 추메/전메로 추가해준다.

public interface State {
    State draw(final Card card);

    State stay();

    Cards cards();

    boolean isFinished();
}

중요) 계산profit() 하려면, 상태객체마다. isBust()인지 / isBlackjack() / isStay() 인지 구현체(상태객체) 종류마다 [isinstanceof 대신 boolean확인메서드]가 필요해지는데???

image-20220324114902170

초대박) isinstanceof 특정 중카(추클)을 대신하는 boolean확인메서드가 아니라 개별 구현체마다 확인이 필요하다면, boolean확인메서드가 구현체 종류마다 필요해지고, 나머지는 모두 예외처리?해야만 한다 -> 개별구현체마다 다른 로직을 가지고 있으면서 && 굳이 (종료상태냐?) 확인할 필요없다면 : 추메/전메 -> [중카무시의 개별구현 책임전과]를 통해 [구현체마다 다른 로직을 구현]해서 다형성에서 알아서 처리되도록 구현하자

암기) 같은 카테고린데, 개별구현해야한다면? isInstanceof (x) -> is특정구현체? (x,그룹일경우만) -> 묻지말고 전략메서드처럼 추메/전메로 개별구현해서 알아서 작동하도록

image-20220324232549837

image-20220324232639391

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에 해당한 애들만 계산로직을 가질 수 있다.

  1. 상태에 따라, 외부input인 배팅금액을 받아 -> 상태마다 개별적으로 다르게 계산해서 새로운 배팅금액을 output으로 응답한다.

    • 이 때, Finished아래의 구현체들만 결과 계산 로직을 가진다.

    image-20220324235238449

my) 계산시 외부재료가 필요한 경우도 있다. 그 외부재료에 계산한 값을 돌려주는 경우가 있다는 것을 생각
참고) 돈 계산의 원시형은 일단 double로 받아서 double로 내어주자
public interface State {
    State draw(final Card card);

    State stay();

    Cards cards();

    boolean isFinished();

    double profit(double money); // 계산 중에 외부에서 받은 것을 계산해서 응답해준다.
}

60) 외부재료받아 계산하는 로직의 [구현체마다 다르게 개별 구현] (finished 아래 구현체들만)

image-20220325000036685

  1. blackjack -> 외부재료(input money)를 * 2 하는 계산후 응답해준다.

    • 개별구현을 위해 중카/추클에서 impl무시하면, 자식들이 불나있다.

      image-20220325000142884

        public final class Blackjack extends Finished {
              
            Blackjack(final Cards cards) {
                super(cards);
            }
              
            @Override
            public double profit(final double money) {
                return money * 1.5;
            }
        }
      
  2. bust : 외부입력만큼, 손해로 작용한다면 * -1을 해주면 된다.

     public final class Bust extends Finished {
        
         Bust(final Cards cards) {
             super(cards);
         }
        
         @Override
         public double profit(final double money) {
             return money * -1;
         }
     }
    

61) 개별 구현체 상태에서의 계산이… 추가 정보가 필요한 상태 -> 임의로 input 그대로 응답해놓는 버릇을 들여보자.

  • 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배만 생각해서 완성한다

63) hit와 ready는 profit계산자체가 불가 -> input있는 계산함수라도 개별구현시 예외처리

@Override
public double profit(final double money) {
    throw new IllegalStateException();
}

대박) 개별구현 하다가 중복코드가 보인다? 무시했던 추클에서 impl -> 후 중복부분만 구현(중클/추카 구현 메서드면 final) && 개별구현체마다 다른 부분 = 개별class들이 아는 부분 -> abstract메서드로 빼서 내려주기

image-20220325094739499

중요) 중카/추클이 무시하고 내려보내 -> 개별 구현된 메서드들 중에서 상수 or 일부분만 중복이어도 -> 중카/추클에서 중복제거용impl 구현시행 &&상수(일부분)만 다시 abstract로 내려보내주기

중요+암기) 개별구현 전과시키려고 [impl구현 무시한 중카/추클 내]에서 새로운 중복 발견인 경우, impl구현 무시한 곳 -> impl시행하여 아래부분 중복제거를 시행하며 -> 상수든 뭐든 구현체별로 달라지는 부분상수라도 -> 메서드응답으로 빼고 -> abstract 메서드로 정의해서 자식들에게 [응답메서드로 상수(일부분) 개별구현]으로 내려주기

64) Finished내부, 상수만 구현체별로 다르고 메서드가 중복된다면? -> 제한된 중카/추클로만 올린 뒤, 달라지는 부분만 메서드로 추출하여 응답받도록 한 뒤 -> abstract메서드로 내려보내서 자식들이 상수응답하도록 하기

image-20220325095200582

  1. Finished에서 무시했던 노필수 impl구현을 해줘서, 중복제거용 코드로 먹어준다.

    image-20220325095241479 image-20220325095256481

    image-20220325095310605

중요) 중카/추클은 상카 존재개별구현 -> 무시하고 내려보내기 or 중복제거 -> final로 막아두고 구현 or 중카/추클 자식들의 중복시 -> 자신이 추메/전메처럼 abstract로 정의해서 뿌려준다. + 상수도 응답 메서드로서 뺀 뒤 -> protected? abstract로 정의하여, 추메/전메처럼 내려준다

  1. **개별 클래스들이 알고 있는 부분(메서드 구현 뿐만 아니라 상수도!!)은 개별 클래스(구현체)들이 응답해줄 abstract메서드로 뺀다 **

    • 상수를 메서드로 뺄 때, 상수이름을 메서드로 네이밍()해주는 센스

    image-20220325095607389 image-20220325095652729

    • 중카/추클에 정의하는데 final로 중복구현 vs 개별구현의 최상위라면, 중복코드는 final로 정의해주되, 내부에 개별구현 코드가 보인다면, 메서드로 뺀 뒤 -> 추메/전메처럼 뿌려주려면, abstract 메서드로 내려주기

      image-20220325095801077

    • 개별구현시키려고 abstract메서드로 뽑았더니, 자식들 구현하라고 protected로 찍혀있다.

      image-20220325102200707

    • abstract로 추메/전메처럼 개별구현으로 내려보내면 -> 자식들 불 들어온다. image-20220325103913176

      image-20220325103928342

암기) 중카-추클이 개별구현을 내려줘야한다면, 중복제거 코드내라도 가능하며, 상수, 일부분이라도 (1) 메서드로 빼고 -> (2)abstract로 내려준다.
  1. 개별 구현체들이 알고 있는 개별 상수들을 메서드로 구현해준다.

    • blackjack

      1. 올린 중복코드는 제거한다. image-20220325105446778

      2. 중복코드를 제외한 상수의 개별구현을 abs -> impl해줘서 응답해준다.

        image-20220325105633867

         public final class Blackjack extends Finished {
                    
             Blackjack(final Cards cards) {
                 super(cards);
             }
                    
             @Override
             protected double earningRate() {
                 return 1.5;
             }
         }
        
    • 나머지 들도, 중복코드를 삭제하고, 상수를 응답하는 개별구현 메서드를 구현한다

      image-20220325110406014

      image-20220325110733677

        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을 보자

image-20220325111156348

  • profit()중복코드로서 중카/추클에서 정의해줬다
    • 중복코드 -> 외부에서 호출할 놈 -> public
  • profit()내에서 구현체별 달라지는 부분(상수)는 내부에서 메서드추출 -> 추카/중클에서 (protected)abstract로 전메/추메처럼 개별구현으로 내려보낸다
    • earningRate()는 개별구현체별 다르게 구현되는 상수를 추출한 메서드

image-20220325111949359

image-20220325120054391

참고) 중카/추클(부모클래스)의 usage(extends)를 확인해보면, 같은 레벨의 자식들만 볼 수 도 있어서 -> 레벨이 맞는지 확인할 수 있다

image-20220325121321953

  • 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();
          }
    

66) 반대편 추클과 동일한 레벨의 추상화(중카/추클) 만든 후, 기존에 개별구현들은 무시하여 자식들에게 전과된 체 두고 + 중복제거용 메서드들만 뽑아서 impl하여 final -> 자식들의 중복코드 제거한다

image-20220323000036426

  1. Finished의 반대 Running(중카/추클)만들기

    image-20220325135456421

중카/추클 생성하는데, 더 위의 중카/추클이, 상태값+생성자 (for getter?) 내려준다면, super()로 내려주는 상태값 초기화는 기본적으로 해줘야함

image-20220325135602358

image-20220325135612199

  • Running <-> Finished

      public abstract class Running extends Started {
          protected Running(final Cards cards) {
              super(cards);
          }
      }
    

67) 추가 중카/추클은 기존 개별구현 메서드들을 제외시키면서 && 중복처리를 해줄 메서드들을 -> [implement Methods...] ->상카의 추메/전메들 중 선택해서 처리한다.

  1. 중간에 추가된 Finished대항마 Runningimpl해서 중복들을 상카-추메/전메중에 확인해서 처리해야한다.image-20220326004301736image-20220326004319447

  2. isFinihsed는 피니쉬의 대항마 추상레이어로서 아래 똑같이 중복 return false

    마찬가지로 profit도 아직 안끝났으면, 수익률계산불가 -> 예외처리를을 중복처리한다. image-20220326004609632 image-20220326004717375

     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 추가한 중카/추클하도록 넘어가자

68) 추클상 정의하는 메서드들은 무조건 접근제한자 확인할 것! 추클상 중복처리한다면, 자식에선 딴짓 못하게 final도 함께!!

image-20220326004809362 image-20220326004907140

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();
    }
}

69) final 중복처리 메서드로 중복처리까지 끝냈다면 -> 새로운 자식들에게 가서 자식들이 extends && 기존 중복코드들 제거해주기

  • Running
    • Hit
    • Stay
1. 새 부모로서 extends image-20220326010751296 image-20220326010820149
  1. 처리된 중복메서드만 삭제(final로 막아놔서 -> extends한 자식은 @Override시 빨간줄) image-20220326010912352

  2. Ready도 똑같이 처리한다.

중요+암기) 추상클래스에서 중복처리시 final을 달아서 처리해주면 -> 기존 개별구현하던 자식들이 extends한 순간부터 딴짓했다고 빨간줄내면서지워달라고 해준다.

70) 최종 다이어그램 확인하기

image-20220326011957666

중요) 추상클래스에서 전메/추메의 abstract가 나온다면, protected로서 자식들이 개별구현하도록 풀어준다. ex> final 중복처리 메서드 내부에서 상수만 개별구현

image-20220326015147128

중요) 상태패턴 최종 기능파악 + 인터페이스로 약속만 정의 -> 바깥에서 인페 추상체 state를 상태값으로 가진다면, 내부 구현 정보를 모르고 사용만 한다. (인페 추상체는 밖에서 주입해도 되고, 내부에서 즈그들끼리 변해도 되고.. 모른다) <-> state를 추클로 정의하면, 바깥에서 내부 정의를 다안다.?

public interface State {
    State draw(final Card card);

    State stay();

    Cards cards();

    boolean isFinished();

    double profit(double money);
}
  1. isFinished()가 판단가능해서
    1. 끝나지 않았으면, 추가정보로 계속 상태변화 draw( )
    2. 끝났으면, 그 상태에서 결과계산 profit( )
  2. stay()주체(Player)가 원할 때, isFinished()에 걸리도록 끝내주고
    • 종료도.. 종료상태를 먼저 만들어주고, isFinished()에 걸려야하는 구나!
  3. cards()출력이나, 상태업데이트를 위해 현재상태를 가져온다

인페는 말그대로 인터페이스만 제공해주고, 내부구현은 모른다. -> 인터페이스로 연결되었다면, Player입장에서는 state 가 어떻게 동작하는지 1도 모른다. (내부동작을 모른다)

  • 인터페이스는 바깥에서 사용할 때, 내부 구현을 모르는 상테로, 약속에만 맞게 동작하는구나정도만 알 수 있다
    • Player -> private State state;로 상태값으로 가지긴 하지만, 인페 객체(추상체)를 갖다쓰는 순간 내부 구현고 직접 구현체가 들어갈 때만 거기에 맞게 작동하므로)
  • 인터페이스가 좋다고 해도, 많아지면 장황해진다
  • 추클과의 논쟁은 끝이 없다.

인페로 정의한 State는 사용자가 내용은 모른체, 원하는 대로 사용할 수 있다.

71) Player가 인터페이스 객체(추상체)의 state를 상태값으로 가지는 순간, 그 내부 구현은 모르게 된다.

  1. state와는 다른 .player패키지 -> Player를 만들기

    image-20220327104900319

  2. State의 사용처는 인페객체 = 추상체상태값으로 가져, 내부구현은 모른다. image-20220327104505110

중요) 상태객체가 단독 public으로 열린 최초시작상태Ready 객체가 있다면, 시작이 그것 밖에 없으니, 생성자가 아니더라도 필드에서 바로 new Ready(); = (최초시작상태 객체)로 초기화`해줘도 된다.

암기) 상태패턴은 필드에서부터 열려있는 접근제어자는 Ready객체 밖에 없어서 private State state = new Ready();로 시작
  1. Ready로 시작할 수 밖에 없다면, 생성자에서 초기화 안하고 필드에서 해도 된다.

    public class Player {
        
        private State state = new Ready();
        
    }
    

    image-20220327105735001

72) 상태사용자 Player 등은, 상태업데이트 메서드 state.draw(card)를 사용하는 메서드를 한번더 만들어줘야한다( 객체를 포장하는 조합처럼). + 이 때, 필요한 재료(card)를 바로 줄지, 아니면 더 바깥상태의 재료를 받아서 내부에서 꺼내서서 넘길지(Deck.pick() -> card)는 사용자 맘이다. -> 어떻게 되었든 Player는 인터페이스로 연결된 State를 모른다.

image-20220327113038534

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);
    }
}

73) 사용자 가 끝나기전 호출가능 메서드들(draw, stay)을 호출하는 메서드를 작성할 때는, 항상 내부에서 현재State가 아직 안 끝난 상태인지 확인후 호출되도록 해야한다.

public interface State {
    State draw(final Card card);

    State stay();

    Cards cards();

    boolean isFinished();

    double profit(double money);
}

image-20220327112607614

image-20220327113038534

74) state사용자가 상태변화메서드draw()의 재료뭉태기를 파라미터로 + while + is끝난상태객체 될대까지로 돌리면 한번에 계속 호출할 수 도 있다.

image-20220327112946101

public class Player {

    private State state = new Ready();

    public void draw(Deck deck) {
        while (!state.isFinished()) {
            state = state.draw(deck.pick());
        }
    }
}

my) 매번 끝났는지 확인가능 + 끝날때까지 재료가 매번 제공되면 -> if로 1동작만 할 것을 -> while로 여러동작할 수 있다.

  • 메서드가 card를 파라미터로 받는다고 해서 외부에서 card를 직접꺼내주지말고, 외부에서는 card덩어리의 객체를 파라미터로 받아보자

    image-20220327113342252

    • Player

      • draw <- Deck ( = cards by .pick() )
        • if ! isFinished()
          • state <- card <- Deck.pick()
        • while ! isFinished()
          • state <- card <- Deck.pick()
      • draw <- card
        • if ! isFinished()
          • state <- card
        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);
                }
            }
        }
      

남은일

  • 상태패턴에서 stay일 때 profit구현(임시로 money 1배로 반환)