[Java] 상태 패턴에 관한 고찰

김민수 / Minsu Kim·2024년 3월 15일
0

[Java]에 대한 고찰

목록 보기
7/7
post-thumbnail

⭐️ 들어가는 말

블랙잭 미션에서 플레이어나 딜러는 특정한 상태를 가진다.
예를 들어, 2장을 뽑는 시작 상태, 카드를 뽑는 Hit 상태, 카드 뽑기를 멈춘 Stand 상태, 2장이 21점인 Blackjack 상태, 점수가 21점을 초과한 버스트 상태가 있다.
bust 상태에서는 draw를 못한다. 또는 hit 상태에서는 draw를 할 수 있다.
이 경우 if문이 굉장히 많이 생기게 된다.
반복되는 조건물을 줄이기 위햇 많이 사용하는 방법은 다형성을 이용하는 것이다.

⭐️ 상태 패턴의 정의

객체가 특정 상태에 따라 행위를 달리하는 경우, 조건문을 통해서 행위를 다르게 하는게 아닌 상태를 객체화해서 상태가 행동할 수 있도록 위임하는 패턴이다.

⭐️ 상태 패턴을 사용하는 방법

우선 interface나 abstract를 만들어 줍니다.

public abstract class State {
    protected Hand hand;

    protected State(Hand hand) {
        this.hand = hand;
    }

    public abstract State draw(Deck deck);

    public abstract State stay();

    public abstract boolean isFinished();

    public int calculateScore() {
        return hand.calculateScore();
    }

    public List<Card> getCards() {
        return hand.getCards();
    }

    public boolean isBlackjack() {
        return hand.isBlackjack();
    }
}

State를 상속한 다양한 상태들을 만들어 줍니다.
여기서 hit인 경우는 다음 상태로 Bust, Hit으로 갈 수 있습니다.
하지만 BustState에서는 draw를 할 수 없습니다.

public class HitState extends State {
    protected RunningState(Hand hand) {
        super(hand);
    }

    @Override
    public boolean isFinished() {
        return false;
    }

    @Override
    public State draw(Deck deck) {
        hand = hand.add(deck.draw());

        if (hand.isBust()) {
            return new BustState(hand);
        }

        return new HitState(hand);
    }

    @Override
    public State stay() {
        return new StandState(hand);
    }
}
public class BustState extends State {
    protected FinishedState(Hand hand) {
        super(hand);
    }

    @Override
    public State draw(Deck deck) {
        throw new UnsupportedOperationException("이미 종료된 상태입니다.");
    }

    @Override
    public State stay() {
        throw new UnsupportedOperationException("이미 종료된 상태입니다.");
    }

    @Override
    public boolean isFinished() {
        return true;
    }
}

이렇게 상태에 따라 할 수 공통으로 정의된 메서스의 행동이 다르게 사용됩니다.

⭐️ 상태 패턴의 장점

  • 확장성: 새로운 상태를 추가하고 싶을 때 기존 코드를 변경하지 않고, 새로운 상태 클래스를 추가하기만 하면 됩니다.
  • 유지보수성: 상태에 따른 행동이 상태 클래스 내부에 캡슐화되어 있어, 특정 상태의 행동을 변경하고 싶을 때 해당 상태 클래스만 수정하면 됩니다.
  • 조건문 제거: 상태에 따른 행동 변화를 조건문 대신 클래스의 다형성을 이용해 처리함으로써 코드의 가독성과 유지보수성을 향상시킵니다.

⭐️ 주의해야할 점

현재 무슨 상태인지 알기 위해서 instance of 를 사용하는 경우가 있다. 하지만 이것은 성능상 문제점이 있기도 하고, OCP, SRP 위반이므로 사용하기에는 별로이다.

⭐️ 결론

상태가 많이 보이는 경우 조건문을 이용하지 말고 상태를 객체화해서 해결해보자!

⭐️ 참고

  1. https://inpa.tistory.com/entry/GOF-%F0%9F%92%A0-%EC%83%81%ED%83%9CState-%ED%8C%A8%ED%84%B4-%EC%A0%9C%EB%8C%80%EB%A1%9C-%EB%B0%B0%EC%9B%8C%EB%B3%B4%EC%9E%90
  2. https://tecoble.techcourse.co.kr/post/2021-04-26-instanceof/
profile
https://alstn113.tistory.com

0개의 댓글