에릭 프리먼 님의 "헤드퍼스트 디자인 패턴" 책을 정리한 포스팅 입니다
1. 상태 기계
- 상태에 따라 시스템의 행동이 달라지고, 상태 전이는 명확하게 정의된 규칙에 따라 일어남
| 구성 요소 | 설명 | 
| 상태 모음 | 시스템이 가질 수 있는 여러 상태들을 정의함 (Idle, Running, Paused, Finished 등) | 
| 상태 표현 변수 | 현재 상태를 나타내는 인스턴스 변수 (State currentState;) 등 | 
| 행동 모음 | 상태에 따라 달라지는 행동들을 정의함 (start(), pause(), reset() 등) | 
예제: GumballMachine
- 만약 상태가 추가될 경우, 상태에 의존하는 모든 코드들에 분기 코드가 추가되어야 함
예제) GumballMachine
더보기
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;    
    
    int state = SOLD_OUT, count = 0;
    
    public GumballMachine(int count) {
    	this.count = count;
        if (count > 0) state = NO_QUARTER;
    }
    
    public void insertQuarter() {
    	if (state == HAS_QUARTER) {
            System.out.println("동전은 한 개만 넣어 주세요");
        } else if (state == NO_QUARTER) {
            state = HAS_QUARTER;
            System.out.println("동전을 넣으셨습니다.");
        } else if (state == SOLD_OUT) {
            System.out.println("매진 되었습니다.");
        } else if (state == SOLD) {
            System.out.println("알맹이를 내보내고 있습니다.");
        } 
    }
    
    public void ejectQuarter() {
    	if (state == HAS_QUARTER) {
            System.out.println("동전이 반환됩니다");
            state = NO_QUARTER;            
        } else if (state == NO_QUARTER) {
            System.out.println("동전을 넣어주세요.");
        } else if (state == SOLD_OUT) {
            System.out.println("동전을 넣지 않았습니다.");
        } else if (state == SOLD) {
            System.out.println("이미 알맹이를 뽑으셨습니다.");
        } 
    }
    
    public void turnCrank() {
    	if (state == HAS_QUARTER) {
            System.out.println("손잡이를 돌리셨습니다.");
            state = SOLD;
            dispense();
        } else if (state == NO_QUARTER) {
            System.out.println("동전을 넣어주세요.");
        } else if (state == SOLD_OUT) {
            System.out.println("매진되었습니다.");
        } else if (state == SOLD) {
            System.out.println("손잡이는 한번만 돌려주세요.");
        } 
    }      
    
    public void dispense() {
        System.out.println("알맹이를 내보내고 있습니다.");
        if (--count == 0) {
            System.out.println("더 이상 알맹이가 없습니다.");
            state = SOLD_OUT;
        } else {
            state = NO_QUARTER;
        }
    }
}
2. 상태 패턴
- 객체의 내부 상태가 바뀜에 따라서 객체의 행동이 달라지는 패턴
구성 요소
| 구성 요소 | 설명 | 
| Context | 현재 상태를 참조하고 상태별 행동을 위임하는 클래스 | 
| State 인터페이스 | 상태별로 공통으로 제공해야 할 메서드를 정의 | 
| ConcreteState 클래스 | 실제 상태별로 State 인터페이스를 구현한 클래스 | 
| 상태 전이 메커니즘 | 상태 클래스 내부에서 다음 상태로 전환 | 
장점
| 장점 | 설명 | 
| 조건문 제거 | if, switch 없이 상태별 동작을 다형성으로 처리 가능 | 
| 행동 캡슐화 | 상태별 행동이 객체로 분리되어 코드가 깔끔하고 명확함 | 
| 상태 전이 명확 | 상태 객체가 스스로 다음 상태를 지정 → 전이 흐름이 명시적 | 
| 유지보수성 향상 | 새로운 상태 추가 시 기존 코드 변경 최소화 가능 (OCP 적용) | 
| 클라이언트가 상태를 몰라도 됨 | context가 상태를 관리하므로, 사용자는 상태에 따른 세부 동작을 몰라도 사용 가능 | 
3. 예제: GumballMachine
State
- 상태를 표현할 인터페이스 정의
- 상태를 표현하는 구현체들을 모두 구현
더보기
public interface State {
    void insertQuarter();
    void ejectQuarter();
    void turnCrank();
    void dispense();
}public class NoQuarterState implements State {
    GumballMachine gumballMachine;
    
    public NoQuarterState(GumballMachine gumballMachine) {
    	this.gumballMachine = gumballMachine;
    }
    
    public void insertQuarter() {
    	System.out.println("동전을 넣으셨습니다.");
        gumballMachine.setState(gumballMachine.getHasQuarterState());
    }
    
    public void ejectQuarter() { System.out.println("동전을 넣어주세요."); }
    public void turnCrank() { System.out.println("동전을 넣어주세요."); }
    public void dispense() { System.out.println("동전을 넣어주세요."); }
}
GumballMachine
더보기
public class GumballMachine {
    State soldOutState, noQuarterState, hasQuarterState, soldState, state;
    int count;
    
    public GumballMachine(int numberGumballs) {
    	soldOutState = new SoldOutState(this);
        noQuarterState = new NoQuarterState(this);
        hasQuarterState = new HasQuarterState(this);
        soldState = new SoldState(this);
    	    	
        this.count = numberGumballs;        
        state = count > 0 ? noQuarterState : soldOutState;
    }
    
    public void insertQuarter() {
    	state.insertQuarter();
    }
    
    public void ejectQuarter() {
    	state.ejectQuarter();
    }
    
    public void turnCrank() {
    	state.turnCrank();
        state.dispense();
    }      
    
    public void releaseBall() {
        System.out.println("알맹이를 내보내고 있습니다.");
        if (count > 0) count--;
    }
}
'Java > Design Pattern' 카테고리의 다른 글
| [헤드퍼스트 디자인 패턴] 12-1. 브리지 패턴 (0) | 2024.12.18 | 
|---|---|
| [헤드퍼스트 디자인 패턴] 11. 프록시 패턴 (0) | 2024.12.18 | 
| [헤드퍼스트 디자인 패턴] 9-2. 컴포지트 패턴 (2) | 2024.12.18 | 
| [헤드퍼스트 디자인 패턴] 9-1. 반복자 패턴 (0) | 2024.12.18 | 
| [헤드퍼스트 디자인 패턴] 8. 템플릿 메서드 패턴 (0) | 2024.12.18 |