회고/우아한테크코스

나는 블랙잭 미션을 통해 무엇을 얻었을까

 

시간이 좀 지나고 회고하는거라 큼지막한 피드백 위주로 회고를 작성해보려 합니다.

 

 

 

 

 

상속하는 객체들과의 관계설정, feat. 추상클래스

Gamer 클래스를 Player, Dealer가 상속받고 있었습니다.

Gamer 클래스를 통해 인스턴스를 생성할 수 있지만 이 행위는 제가 의도하지 않은 행위였습니다.

 

abstract를 모르고 상속을 사용했기 때문에 이러한 피드백이 왔다고 생각합니다.

 

객체간의 공통점이 보인다면 묶을 수 있습니다.

 

묶는 방법은 대표적으로

  • 상속 : 동일하게 행동하는 인스턴스를 그룹화해 계층적으로 설계하고 싶다면 사용한다.
  • 조합 : 단순히 공통메서드를 묶고 싶을 때 사용한다.

이 있습니다.

 

상속을 이용한다면 상위클래스 자체로 인스턴스를 생성하는 것을 막기 위해 상위 클래스를 abstract로 선언해야합니다.

클래스 명도 Gamer에서 Role로 바꿨습니다. 😅

 

 

 

 

 

 

remove()를 할 때 일어나는 일

package blackjack.domain.card;

import blackjack.domain.card.property.CardNumber;
import blackjack.domain.card.property.CardShape;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CardPack {
    private final List<Card> cards = new ArrayList<>();

    ..생략..
    
    public Card pickOne() {
        if (cards.isEmpty()) {
            initializeCards();
        }

        return cards.remove(0);

 

ArrayList의 remove 동작은 아래와 같습니다.

private void fastRemove(Object[] es, int i) {
        modCount++;
        final int newSize;
        if ((newSize = size - 1) > i)
            System.arraycopy(es, i + 1, es, i, newSize - i);
        es[size = newSize] = null;
    }


"사이즈가 하나 작은 리스트를 생성해 해당 원소만 빼고 다시 copy한다."

이것은 곧 remove()를 매번 수행하면 성능저하로 이어질 수 있다는 뜻이었습니다.



해결방법
- LinkedList의 remove는 arrayList보다 remove 로직이 간단하다. 연결된 노드를 끊는다.
- 추가로 카드 52장을 한번 생성하고 추가로 생성하지 않기 위해 static List로 cards를 갖고있게 한다.

private final List<Card> cardPack = new LinkedList<>();

 

 

 

 

 

컨트롤러의 멤버변수

 

처음에 리뷰를 받았을 때 피드백을 주신 의도를 파악하지 못했습니다.

단지 컨트롤러의 여러 메서드에서 사용하기 때문에 매번 매개변수로 넘겨주기 싫은 이유밖에 없었습니다.

 

 

이 피드백의 의도를 파악하기 위해선 실제 컨트롤러의 역할에 대해 알고있어야 했습니다.

 

컨트롤러

MVC 패턴중 C(Controller)에 해당합니다.

사용자의 요청이 진입하는 지점이며, Model에게 데이터를 요청해 View로 전달하는 역할을 합니다.

 

그래서 컨트롤러는 무상태를 유지해야합니다.

 

 

만약 컨트롤러가 멤버변수를 가지고있는 상태에서 여러 사용자가 컨트롤러에 접근한다면, 여러 사용자가 같은 객체를 공유하게 됩니다.

(위 블랙잭 게임에선 내 패에 다른 누군가가 카드를 추가할 수 있겠죠..)

 

 

 

 

 

각자의 책임분리, 협력하는 방식

sum을 받아서 bust인지 확인함

 

왼) 굳이 저렇게?      오) 객체에게 메세지 보내기

 

이 피드백을 기점으로 "객체에게 메세지를 보내라" 라는 의미를 제대로 이해했습니다.

 

굳이 Dealer에게 sum을 받아서 Player에게 Dealer가 Bust인지 확인한다?

-> Dealer에게 Bust인지 물어보면 된다.

 

getter가 있는 곳에는 객체의 책임분리가 덜 되어있을 확률이 매우 크다는 것도 깨달았습니다.

 

 

 

 

 

네오의 상태패턴 강의

 

블랙잭 미션을 if문 없이 완성할 수 있는 고퀄리티 강의를 보고 경악을 금치 못했습니다.

이 날 저는 상태패턴 수업을 듣고 제 코드를 수정할 수 없는 상태에 빠졌습니다.

 

 

강의내용

  • 객체는 상태를 가지고 있다.
  • 갖고있는 상태에게 메서드를 던지고 상태는 메서드를 수행한뒤 다음 상태를 반환한다.

 

학교 수업때 배운 오토마타와 개념이 비슷했습니다.

 

블랙잭에선

addCard()를 하더라도

 

  • Hit인지,
  • BlackJack인지,
  • Stay인지,
  • Bust인지

에 따라 addCard()의 동작이 달라집니다.

 

아쉽게도 상태패턴은 블랙잭미션에 도입하지 못했지만 체스미션엔 꼭 도입하겠다고 다짐했습니다.