해당 포스팅은 한빛 미디어 헤드퍼스트 디자인 패턴(에릭 프리먼, 엘리자베스 롭슨 저)를 통해 공부한 내용을 정리한 블로그입니다.
아직 많이 부족하고 배울게 너무나도 많습니다. 틀린내용이 있으면 언제나 가감없이 말씀해주시면 감사하겠습니다😁
좋은 프로그래머는 자기 두뇌를 사용한다. 그러나 좋은 가이드라인은 모든 케이스를 고려해야만 하는 노력을 줄여준다.
(Francis Glassborow, 개발자)
전략 패턴과 상태 패턴은 쌍둥이
- 상태 다이어그램과 비슷
- 다른 상태로 전환을 위해서는 어떤 동작이 필요
- 예외 케이스에 대해서도 항상 잘 생각해야함.
- 상태 값을 저장하는 인스턴스 변수를 만들고 메소드 내에서 조건문을 써서 다양한 상태를 처리
State Diagram
상태
- 동전 없음
- 동전 있음
- 알맹이 없음
- 알맹이 판매
상태를 저장하는 인스턴스 변수 정의
/*
* 알맹이 상태 저장
*/
final static int SOLD_OUT = 0; // 알맹이 없음
final static int NO_QUARTER = 1; // 동전 없음
final static int HAS_QUARTER = 2; // 동전 있음
final static int SOLD = 3; // 알맹이 내보내는 중
시스템에서 일어날 수 있는 모든 행동 정의
- 동전투입
- 동전 반환
- 손잡이 돌림
- 알맹이 내보냄
클래스 만들기
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;
int 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 { // state == SOLD
System.out.println("알맹이를 내보내는 중");
}
}
// 이후 부터는 행동 정의 생략...
/*
* 동전 반환
*/
public void ejectQuarter() {
}
/*
* 손잡이를 돌리는 경우
*/
public void turnCrank() {
}
/*
* 알맹이 내보내기
*/
public void dispense() {
}
public void refill(int numGumBalls) {
}
}
뽑기 기계 수정 요청
- 새로운 기능 추가 요구
- 현재 코드 ⇒ 관리 및 수정의 어려움
- 상태 별 행동을 별도의 클래스에 넣어두고 모든 상태에 대해 각각 자기가 할 일을 구현
- ⇒ 바뀌는 부분을 캡슐화
- 뽑기 기계가 현재 상태를 나타내는 상태 객체에게 작업을 넘기도록 ⇒ 구성
새로운 디자인 구성하기
- 기존 코드를 그대로 활용하는 대신 상태 객체들을 별도의 코드에 넣고 어떤 행동이 일어나면 현재 상태 객체에서 필요한 작업을 처리.
- 뽑기 기계와 관련된 모든 행동에 관한 메소드가 들어있는 State 인터페이스 정의
- 기계의 모든 상태를 대상으로 상태 클래스 구현.
- 상태에 대해서는 상태 클래스가 모든 책임을 갖도록
- 조건문 코드 없애고 상태 클래스에 작업 위임.
- 상태 패턴 적용
구조 살펴보기
- 해당 결과 도출
- 각 상태의 행동을 별개의 클래스로 국지화
- 관리하기 힘든 분기문 삭제
- 상태를 변경에는 닫혀있고 새로운 상태를 추가하는 확장에는 열려있도록. (OCP적용)
- 이해하기 좋은 코드 베이스와 클래스 구조 적용
public class GumballMachine {
/*
* 알맹이 상태 저장
*/
State soldOutState; // 알맹이 없음
State noQuarterState; // 동전 없음
State hasQuarterState; // 동전 있음
State soldState; // 알맹이 내보내는 중
State state;
int count = 0;
public GumballMachine(int count) {
soldOutState = new SoldOutState(this);
noQuarterState = new NoQuarterState(this);
hasQuarterState = new HasQuarterState(this);
soldState = new SoldState(this);
this.count = count;
if (count > 0) {
state = noQuarterState;
} else {
state = soldOutState;
}
}
/*
* 동전이 투입된 경우
*/
public void insertQuarter() {
state.insertQuarter();
}
/*
* 동전 반환
*/
public void ejectQuarter() {
state.ejectQuarter();
}
/*
* 손잡이를 돌리는 경우
*/
public void turnCrank() {
state.turnCrank();
state.dispense();
}
// State 생성
void setState(State state) {
this.state = state;
}
}
// State 예시
public interface State {
// 동전을 넣었을 때의 상태 정의
public void insertQuarter();
// 동전을 반환했을 때의 상태 정의
public void ejectQuarter();
// 손잡이를 돌렸을 때의 상태 정의
public void turnCrank();
// 알맹이가 나올 때의 상태 정의
public void dispense();
public void refill();
}
public class HasQuarterState implements State {
GumballMachine gumballMachine;
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("동전을 한개만 넣어주세요");
}
@Override
public void ejectQuarter() {
System.out.println("동전을 반환합니다");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
@Override
public void turnCrank() {
System.out.println("손잡이를 돌리셨습니다.");
gumballMachine.setState(gumballMachine.getSoldState());
}
@Override
public void dispense() {
System.out.println("동전을 넣어주세요");
}
public void refill() {}
}
State Pattern
💡 상태 패턴
객체의 내부 상태가 바뀜에 따라서 객체의 행동을 바꿀 수 있음. 클래스가 바뀌는 것과 같은 결과
- 상태를 별도의 클래스로 캡슐화
- 상태 패턴과 전략 패턴은 비슷!!
- 하지만 용도가 다름
- 상태 패턴
- 상태 객체에 일련의 행동이 캡슐화
- 여러 상태 객체 중 하나의 상태에 모든 행동을 맡기게 됨.
- 그에 따라 객체가 바뀌게 될 수도 있음
- 전략 패턴
- 클라이언트가 context 객체에게 어떤 전략을 사용할 지를 지정
- 실행 시에 전략 객체를 변경할 수 있는 유연성을 제공하는 용도로 사용.
- 서브클래스를 만드는 방법을 대신해 유연성 극대화 ⇒ 구성
'기타 > 디자인패턴' 카테고리의 다른 글
[Design Pattern] Combined Pattern (0) | 2024.06.10 |
---|---|
[Design Pattern] Proxy Pattern (2) | 2024.06.10 |
[Design Pattern] Iterator Pattern & Composite Pattern (0) | 2024.06.09 |
[Design Pattern] Template Method Pattern (0) | 2024.06.05 |
[Design Pattern] Adapter Pattern (0) | 2024.06.04 |