상태 패턴

토마스·2023년 3월 13일
0
post-thumbnail

블랙잭 미션을 하던 중 한 가지 문제가 있었다.
블랙잭 결과를 생성하려면 딜러와 플레이어가 게임이 끝난 상태가 되어있어야 한다는 조건을 BlackjackResult 클래스 코드에 명확하게 표현하고 싶었는데, 좋은 방법을 찾지 못했다. 그래서 어쩔 수 없이 딜러와 플레이어의 카드 개수가 2장 이상이고 딜러의 점수가 16점 이하가 아닌지 체크해서 만약 이 조건을 만족하지 않는다면 딜러나 플레이어들 중 게임이 끝난 상태가 아니라고 판단하고 블랙잭 결과를 생성할 수 없도록 구현했다.
그러던 중 수업시간에 상태 패턴이라는 디자인 패턴을 배우고 이 패턴을 블랙잭 미션에 적용하며 공부해보았다.

상태 패턴이란?

상태 패턴은 일련의 규칙에 따라 객체의 상태를 변화시켜, 객체가 할 수 있는 행위를 바꾸는 패턴을 말한다. 어떤 상태로 변하게 할 지 결정하는 주체는 상태를 소유한 객체가 아니라 상태 그 자체이다. 상태를 소유한 객체는 상태에게 같은 메세지를 보내면 상태는 스스로 상태에 맞는 행위를 한다.

예제

블랙잭 미션에서 상태 패턴을 적용한 예제이다.

상태를 소유한 객체인 Participant에서는 State 인터페이스에 정의된 메서드만 사용해도 비즈니스 로직에 맞는 상태로 변경되고 상태에 맞는 메서드가 실행된다. 상태의 구체 클래스에 의존하는 게 아니라 인터페이스에 의존하고 있으니 DIP(의존성 역전 원칙)을 지킬 수 있게 된다.

고려해야 할점

  • 하나의 상태를 클래스 하나로 명확히 표현하는 것과, 상태 변수의 값으로 표현하는 것 사이에서 저울질해봐야 한다.
    • 클래스로 명확히 표현하는 것이 낫다면 스테이트 패턴으로의 리팩토링을 고려할 수 있다.
    • 상태 패턴으로 리팩토링을 한 결과가 더 복잡하다면 굳이 스테이트 패턴을 도입하지 않아도 된다.
  • 상태 패턴은 if/else/when 같은 분기문을 효과적으로 제거할 수 있다.
  • 클래스의 수가 취급해야 하는 상태의 수만큼 추가로 늘어난다는 점에 주의해야 한다.
  • 각 상태가 자신의 다음 상태를 알아야 한다는 특징이 있다.
  • 각 상태를 싱글톤으로 관리하는 것도 고려할 수 있다.
    • 코틀린에서는 enum으로 관리할 수 있다.
class WaterMachine {
    private var state: WaterMachineState = WaterMachineState.NORMAL

    fun clickStateButton() {
        state = state.click()
    }

    fun getWater() {
        println("물이 나오는 중")
    }
}

enum class WaterMachineState {
    NORMAL {
        override fun click(): WaterMachineState {
            return COLD
        }
    },
    COLD {
        override fun click(): WaterMachineState {
            return HOT
        }
    },
    HOT {
        override fun click(): WaterMachineState {
            return NORMAL
        }
    }, ;

    abstract fun click(): WaterMachineState
}

정수기의 버튼을 누르면 상태가 변경된다. 그리고 물을 나오게 하면 상태에 맞는 물이 나오게 된다. 이처럼 상태가 가져야할 인스턴스 변수가 없거나, 인스턴스 변수가 고정되어 있다면 enum class로 선언할 수도 있다.

profile
안드로이드 개발자 지망생

0개의 댓글

관련 채용 정보