1. 정의
- 내부 상태가 바뀜에 따라 객체의 행동이 바뀔 수 있게 한다. 마치 객체의 클래스가 바뀌는 것 같은 결과를 얻을 수 있다.
2. 예시
- 알맹이 뽑기 기계를 만든다.
3. 그림
4. 클래스 다이어그램
5. 코드
public class Client {
public static void main(String[] args){
GumballMachine machine = new GumballMachine(3);
machine.insert();
machine.eject();
for(int i=0; i<3; i++) {
System.out.println("------");
machine.insert();
machine.turn();
}
System.out.println("------");
machine.insert();
}
}
/* 출력
동전을 넣었습니다.
동전을 반환합니다.
------
동전을 넣었습니다.
손잡이를 돌렸습니다
알맹이를 내보냈습니다.
------
동전을 넣었습니다.
손잡이를 돌렸습니다
알맹이를 내보냈습니다.
------
동전을 넣었습니다.
손잡이를 돌렸습니다
알맹이를 내보냈습니다.
알맹이가 매진되었습니다.
------
알맹이가 매진되어 동전을 넣어도 뽑을 수 없습니다.
*/
public interface State {
void insert();
void eject();
void turn();
void dispense();
}
public class NoState implements State{
GumballMachine machine;
public NoState(GumballMachine machine) {
this.machine = machine;
}
@Override
public void insert() {
System.out.println("동전을 넣었습니다.");
machine.setState(machine.has);
}
@Override
public void eject() {
System.out.println("동전이 없어 동전을 뺄 수 없습니다.");
}
@Override
public void turn() {
System.out.println("동전이 없어 기계를 돌릴 수 없습니다.");
}
@Override
public void dispense() {
System.out.println("동전이 없어 알맹이를 뽑을 수 없습니다.");
}
}
public class HasState implements State{
GumballMachine machine;
public HasState(GumballMachine machine) {
this.machine = machine;
}
@Override
public void insert() {
System.out.println("이미 동전이 기계에 있어 넣을 수 없습니다.");
}
@Override
public void eject() {
System.out.println("동전을 반환합니다.");
machine.setState(machine.no);
}
@Override
public void turn() {
System.out.println("손잡이를 돌렸습니다");
machine.setState(machine.sold);
}
@Override
public void dispense() {
System.out.println("알맹이를 내보낼 수 없습니다. 손잡이를 돌려주세요.");
}
}
public class SoldState implements State{
GumballMachine machine;
public SoldState(GumballMachine machine) {
this.machine = machine;
}
@Override
public void insert() {
System.out.println("알맹이를 내보내고 있어 동전을 집어넣을 수 없습니다.");
}
@Override
public void eject() {
System.out.println("알맹이가 뽑히고 있어 동전을 반환할 수 없습니다.");
}
@Override
public void turn() {
System.out.println("손잡이는 한 번만 돌려주세요.");
}
@Override
public void dispense() {
machine.releaseBall();
if(machine.count > 0){
machine.setState(machine.no);
}else{
System.out.println("알맹이가 매진되었습니다.");
machine.setState(machine.soldOut);
}
}
}
public class SoldOutState implements State{
GumballMachine machine;
public SoldOutState(GumballMachine machine) {
this.machine = machine;
}
@Override
public void insert() {
System.out.println("알맹이가 매진되어 동전을 넣어도 뽑을 수 없습니다.");
}
@Override
public void eject() {
System.out.println("알맹이가 매진되었고, 삽입된 동전이 없습니다.");
}
@Override
public void turn() {
System.out.println("알맹이가 매진되어 돌릴 수 없습니다.");
}
@Override
public void dispense() {
System.out.println("알맹이가 매진되어 뽑을 수 없습니다.");
}
}
public class GumballMachine {
State soldOut; // 알맹이 매진
State no; // 동전 없음
State has; // 동전 있음
State sold; // 알맹이 뽑기
State state;
int count = 0;
public GumballMachine(int count) {
soldOut = new SoldOutState(this);
no = new NoState(this);
has = new HasState(this);
sold = new SoldState(this);
this.count = count;
if(count > 0){
state = no;
}else{
state = soldOut;
}
}
public void setState(State state) {
this.state = state;
}
public void insert(){
state.insert();
}
public void eject(){
state.eject();
}
// 돌리기와 알맹이 뽑기는 동시에 진행됨
public void turn(){
state.turn();
state.dispense();
}
public void releaseBall(){
System.out.println("알맹이를 내보냈습니다.");
if(count>0) count--;
}
}
https://github.com/kang-seongbeom/design_pattern
💡 Github에서 디자인 패턴 코드를 볼 수 있습니다.
6. 설명
- GumBallMachine은 State 참조변수에게 처리를 위임한다.
- State 참조변수에 어떤 인스턴스가 저장되었느냐에 따라 행동이 달라진다.
- 즉, 내부 상태가 바뀜에 따라 행동이 달라진다.
'디자인 패턴' 카테고리의 다른 글
디자인 패턴 - 브릿지 패턴(Bridge Pattern) (0) | 2022.11.18 |
---|---|
디자인 패턴 - (원격)프록시 패턴 (Proxy Pattern) (0) | 2022.11.18 |
디자인 패턴 - 컴포지트 패턴(Composite Pattern) (0) | 2022.11.18 |
디자인 패턴 - 반복자 패턴(Iterator Pattern) (0) | 2022.11.18 |
디자인 패턴 - 템플릿 메소드 패턴(Template Method Pattern) (0) | 2022.11.17 |