에릭 프리먼 님의 "헤드퍼스트 디자인 패턴" 책을 정리한 포스팅 입니다
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 |