👀 학습 목표
- 스테이트 패턴을 이해한다.
- 스트래티지 패턴: 바꿔 쓸 수 있는 행동을 캡슐화한 다음, 실제 행동은 다른 객체에 위임합니다.
- 스테이트 패턴: 상태를 기반으로 하는 행동을 캡슐화하고 행동을 현재 상태한테 위임합니다.
- 스테이트 패턴 예제를 이해한다.
1. 스테이트 패턴 정의
1-1. 스테이트 패턴이란
객체의 내부 상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있다. 마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있다.
sourcemaking 이미지 참고
2. 스테이트 패턴 적용하기
2-1. 주식회사 왕뽑기 요청
아래와 같이 주식회사 왕 뽑기를 개발해 달라는 요청이 왔습니다. o 는 상태를 의미하고, → 는 다른 상태로 넘어가기 위한 행동입니다.
Head first design patterns 이미지
2-2. 상태 기계의 기초
앞에 다이어그램을 가지고 상태 기계를 구현하는 방법에 대해 살펴보자.
- 4개의 상태: 동전 있음, 동전 없음, 알맹이 매진, 알맹이 판매
- 현재 상태를 저장하기 위한 인스턴스 변수를 만들고 각 상태의 값을 정의
- 이 시스템에서 있을 수 있는 모든 행동을 모아 본다.
- 동전 투입, 동전 반환, 손잡이 돌림, 알맹이 내보냄
- insertQuarter, ejectQuarter, turnCrank, dispense
- 각 행동을 구현할 때, 조건문을 써서 상태별로 어떤 작업을 할지 결정합니다.
상태 기계 기초를 바탕으로 코드 작성
- GumballMachine 클래스 정의
- TEST
2-3. 변경 요청이 들어 왔어요.
10분의 1의 확률로 공짜 알맹이를 받도록 변경해 달라고 합니다.( 총 2개 알맹이가 나오도록) 다이어그램은 아래와 같습니다.
Head first design patterns 이미지
만약 현재 코드에 상태를 한 개 더 추가한다면…?
- 모든 메소드에 해당 상태에 대한 조건문을 추가해야 합니다. 이런 식으로 개발하면 기존 코드에 없던 새로운 버그가 생길 수도 있습니다.
2-4. 새로운 디자인으로 적용하기
새로운 디자인 적용하기(스테이트 패턴 적용하기)
상태 객체들을 별도의 코드에 집어넣고 어떤 행동이 일어나면 현재 객체에서 필요한 작업을 처리하도록 변경합시다. 그러면 새로운 상태가 추가되도 새로운 상태 클래스만 구현하면 되기 때문에 기존 코드는 영향이 없습니다. 계획은 아래와 같습니다.
state 인터페이스 및 클래스 정의
- State 인터페이스 정의
- NoQuarterState 클래스 정의
- HasQuarterState 클래스 정의
- SoldState 클래스 정의
- dispense(): 알맹이 내보내고, 알맹이 수에 따른 상태 변경
- SoldOutState 클래스 정의
- GumballMachine 클래스 변경
2-5. 공짜 알맹이 당첨 기능 추가하기
WinnerState 클래스를 추가해서 당첨 기능을 넣어 봅니다. SoldState에서 두 번 보내면 되지만, 한 클래스에는 단일 역할만 하도록 해야 합니다.(단일 원칙)
- GumballMachine 클래스 수정
- winnerState 상태 관련 추가
- WinnerState 클래스 추가
- HasQuarterState 수정
- 당첨 기능 넣기 : 난수 변수와 turnCrank() 메소드 수정
- 테스트
참고
- Head first design patterns 책