이번 시간에는 스테이트 패턴(State Patter)에 대해서 알아보겠습니다.
사탕 뽑기 기계 프로그램을 구현한다고 가정하면 사탕뽑기 기계는 '동전없음', '동전있음', '상품배출', '상품품절' 상태를 가질 것입니다.
그리고, 사탕뽑기의 각 상태는 아래와 같은 행위를 통해서 다른 상태로 변이하게 됩니다.
이 행위들과 상태를 코드로 구현하면 아래와 같이 구현할 수 있을껍니다.
public class GumBallMachine { final static int SOLD_OUT = 0; final static int NO_QUARTER = 1; final static int HAS_QUARTER = 2; final static int SOLD = 3; private int numberOfGumBall = 0; public int state = SOLD_OUT; public GumBallMachine(int numberOfGum) { if(numberOfGum > 0) { state = NO_QUARTER; } } public int getNumberOfGumBall() { return numberOfGumBall; } public void insertQuarter() { // 동전삽입 시 동작 구현 } public void returnQuarter() { // 동전반환 시 동작 구현 } public void turnCrank() { // 뽑기 손잡이를 돌릴 때 동작 구현 } public void dispense() { // 상품 배출 시 동작 구현 } }
그리고, 행위를 수행했을 때 상태에 따라 벌어지는 일들이 다르기 때문에 상태를 비교하여 분기하는 분기코드가 반복되어 들어가게 됩니다.
쉽게 예를 들어 설명하면 '동전없음' 상태 일 때 insertQuarter()의 실행결과와 '동전있음' 일 때의 실행결과가 다르다는 이야기 입니다.
'동전없음' 일 경우는 동전이 정상적으로 삽입되고, '동전있음' 상태로 변경되면 되겠고, '동전있음' 상태라면 동전이 있다고 경고 메시지를 띄워주는 식의 구현을 해야겠지요.
따라서, 아래와 같은 분기코드가 반복됩니다.
if(상태 == 동전있음) {
} else if(상태 == 동전없음) {
} else if(상태 == 상품배출) {
} else if(상태 == 상품품절) {
}
이런 반복문을 각 상태에 따른 클래스에 캡슐화 하여 각자 자기의 역할을 구현하게 하는 것이 바로 스테이트(State) 패턴입니다.
스테이트 패턴의 다이어그램은 아래와 같습니다.
즉, 아래와 같이 아래와 같이 각 행위들을 인터페이스로 작성한 뒤에 각 상태 클래스에서 구체화 시킵니다.
public interface State { public void insertQuarter(); public void returnQuarter(); public void turnCrank() ; public void dispense() ; } public class SoldState implements State { private GumBallMachine gumBallMachine; public SoldState(GumBallMachine gumBallMachine) { this.gumBallMachine = gumBallMachine; } @Override public void insertQuarter() { System.out.print("잠깐만 기다려주세요. 상품이 나오고 있습니다."); } @Override public void returnQuarter() { System.out.print("삽입된 동전이 없습니다."); } @Override public void turnCrank() { System.out.print("상품이 나오고 있습니다. 손잡이는 이미 돌리셨습니다."); } @Override public void dispense() { gumBallMachine.releaseGumBall(); System.out.print("상품을 꺼냈습니다."); if(gumBallMachine.getNumberOfGumBall() > 0 ) { gumBallMachine.setState(gumBallMachine.getNoQuarterState()); } else { System.out.print("상품이 모두 팔렸습니다."); gumBallMachine.setState(gumBallMachine.getSoldOutState()); } } }
이렇게 하면 상태가 추가, 수정되더라도 수정이 용이한 코드로 탈바꿈하게 됩니다.
정리해서 이야기 하면, 스테이트 패턴은 객체의 내부상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있습니다.
마치 객체의 클래스가 바뀌는 것과 같은 결과를 얻을 수 있습니다
스트래티지 패턴 VS 스테이트 패턴
일반적으로 스트래티지 패턴은 서브클래스를 만드는 방법을 대신하여 유연성을 극대화하기 위한 용도로 쓰입니다.
상속을 이용해서 클래스의 행동을 정의하다 보면 행동을 변경해야할 때 마음대로 변경하기가 힘들죠.
하지만 스트래티지 패턴을 사용하면 구성을 통해 행동을 정의하는 객체를 유연하게 변경할 수 있습니다.
스테이트 패턴은 컨텍스트 객체에 수많은 조건문을 집어 넣는 대신에 사용할 수 있는 패턴이라고 보면 됩니다.
행동을 상태 객체 내에 캡슐화 시키면 컨텍스트 내의 상태 객체를 바꾸는 것만으로도 컨텍스트 객체의 행동을 바꿀 수 있습니다.
전체 소스 : https://github.com/JunpilPark/DesignPatternStudy/tree/master/statePattern/src/main/java/com/example/statepattern
'Tech & Programming > Pattern & Design' 카테고리의 다른 글
템플릿 메소드 패턴(template method pattern) 이란? (0) | 2019.01.18 |
---|---|
팩토리 패턴(Factory Pattern) 이란? (0) | 2019.01.16 |
프록시 패턴(proxy pattern) 이란? (0) | 2019.01.14 |
이터레이터 패턴 (Iterator Pattern) 이란? (0) | 2019.01.10 |