Design Pattern
상태 패턴
bright jazz music
2022. 9. 16. 08:15
상태 패턴은 특정 상태에 따라 행동이 달라지는 객체를 위한 패턴.
쉽게는 리모콘이 예다.
티비의 상태에 따라(켜/꺼)에 따라 버튼이 작동이 다르다.
- 켜: 채널
- 꺼: 채널
블로그도 마찬가지,
비공개 상태( 드래프트 상태)일 때의 포스팅은 클릭할 수도 없고 URL을 입력한다고 접근할 수 없다.
공개가 되면 다른 사람들이 와서 댓글/조항요도 누를 수 있다.
--> 상태 변경에 따라 특정 오브젝트들의 행동이 바뀌는데,
이를 스테이트 패턴으로 정리할 수 있다.
----------------------------
전략패턴과 상태패턴은 쌍둥이다.
- 전략패턴은 바꿔 쓸 수 있는 알고리즘을 사용한다.
- 상태패턴은 내부 상태를 바꿈으로써 객체가 행동을 바꿀 수 있도록 한다.
예를 들어 동전 뽑기 기계
두 가지 상태
- 동전 없음(초기상태).
- 동전 있음.
동전 없음 ==> 동전 투입 ==> 동전 있음(상태 전환)
동전 있음 상태 ==> 손잡이 회전 ==> 알맹이 판매
동전 없음 ==> 동전 투입 ==> 동전 있음(상태 전환)
동전 있음 ==> 손잡이 돌림 ==>알맹이 존재 ? 알맹이 판매 : 동전 반환
초기 디자인
package com.study.study_project.statePattern;
public class GumballMachine {
//껌 기계 클래스
// 총 4개의 상태가 존재 : 각 상태마자 유일한 정수 부여
final static int SOLD_OUT = 0; //알맹이 매진
final static int NO_COIN = 1; //동전 없음
final static int HAS_COIN = 2; //동전 있음
final static int SOLD =3; // 알맹이 판매
int state = SOLD_OUT; //현재 상태를 저장하는 인스턴스 변수
//최초에는 뽑기 기계에 아무런 알맹이가 없으므로 매진 상태로 설정
int count = 0; //알맹이 개수
//행동 4개
//동전 투입, 동전 반환, 손잡이 회전, 알맹이 내보냄.
// 이런 행동 실행 시 상태 변환됨. 행동은 해당 클래스의 인터페이스라고 할 수 있다.
//생성자: 초기 알맹이 개수를 파라미터로 받음.
public GumballMachine(int count) {
this.count = count;
if (count > 0) {
state = NO_COIN;
//입력된 알맹이 개수가 0보다 크면 상태가 NO_COIN으로 변환됨. 알맹이는 있지만 동전은 없는 상태.
// 입력값이 0이면 상태는 여전히 SOLD_OUT
}
}
public void insertCoin() {
if (state == HAS_COIN) { //동전히 투입되어 있는 경우
System.out.println("동전은 한 개만 넣어 주세요"); //동전이 이미 들어 있으므로.
}else if(state == NO_COIN) { //동전히 들어 있지 않은 경우
state = HAS_COIN;// "동전 있음"으로 상태변경
System.out.println("동전을 넣으셨습니다.");
}else if (state == SOLD_OUT) {//매진 상태
System.out.println("알맹이가가 매진되었습니다.나중에 이용하세요."); //동전 반환
}else if (state == SOLD){
System.out.println("알맹이를 내보내고 있습니다.");
}
}
public void ejectCoin(){
if(state == HAS_COIN){
System.out.println("동전이 반환됩니다.");
state = NO_COIN;
}else if(state == NO_COIN){
System.out.println("동전이 없습니다. 동전을 넣어주세요.");
}else if (state == SOLD){
System.out.println("이미 알맹이를 뽑으셨습니다.");
}else if (state == SOLD_OUT){
System.out.println("동전을 넣지 않으셨습니다. 동전이 반환되지 않습니다.");
}
}
public void turnCrank() {
if (state == SOLD) {
System.out.println("손잡이는 한 번만 돌려주세요");
}else if(state == NO_COIN) {
System.out.println("동전을 넣어 주세요");
}else if (state == SOLD_OUT) {
System.out.println("매진 되었습니다");
}else if (state == HAS_COIN){
state = SOLD; //상태를 내보내는 중인 SOLD로 변환
dispense();
}
}
public void dispense(){
if (state == SOLD) {
System.out.println("알맹이를 내보내는 중입니다.");
count = count - 1; //알맹이 개수 한 개 줄이기
if (count == 0){
state = SOLD_OUT; //책에는 상태 변환이 메시지 출력보다 나중에 나온다.
System.out.println("알맹이가 매진되었습니다.");
} else { //남은 수량이 0이 아니라면
state = NO_COIN;
}
}else if (state == NO_COIN){ //오류 방지1: 동전이 없는데 dispense()가 호출되어서는 안 된다.
System.out.println("동전을 넣어 주세요.");
}else if (state == SOLD_OUT) {//오류 방지2: 매진인데 dispense()가 호출되어서는 안 된다.
System.out.println("매진입니다.");
}else if (state == HAS_COIN) {//오류 방지3: 손잡이 안 돌렸는데 dispense()가 호출되어서는 안 된다.
System.out.println("알맹이를 내보낼 수 없습니다.");
}
}
}