2015년 9월 20일 일요일

클래스 디자인 패턴 10. state pattern_

1. 개념잡기
  1) 의미 및 구현방법
      현재 상태에 따라 다른 동작을 보일때 if 구문으로 처리하면
        됩니다.
      그 if 구문의 원인이 되는 상태값이나 상태 기준이 계속 바뀐다면
        그땐 if 구문이 계속 뜯어고쳐지는 상태가 반복됩니다.
      이때 state 패턴으로 해당 if 구문을 치환 가능합니다.
      의미상 이렇지만 실제 생김새를 보면 스트레이트 패턴과 거의
        일치합니다.

  2) 참고자료
http://hongjinhyeon.tistory.com/50


2. 소스
 
  1) state 인터페이스 작성
      해당 인터페이스가 각 상태를 정의함

 
package stateI;

public interface State {
 public void insertQuarter();
 public void ejectQuarter();
 public void turnCrank();
 public void dispense();
} 


  2) state를 implements 한 각 상태 관련 객체들

 
package stats;

import instances.GumballMachine;
import stateI.State;

public class HasQuarterState implements State {
 transient GumballMachine gumballMachine;

 public HasQuarterState(GumballMachine gumballMachine){
  this.gumballMachine=gumballMachine;
 }
 
 @Override
 public void insertQuarter() {
  System.out.println("You can't insert another quarter");
 }

 @Override
 public void ejectQuarter() {
  System.out.println("Quarter returned");
        gumballMachine.setState(gumballMachine.getNoQuarterState());
 }

 @Override
 public void turnCrank() {
  System.out.println("You turned...");
  gumballMachine.setState(gumballMachine.getSoldState());
 }

 @Override
 public void dispense() {
  // TODO Auto-generated method stub
  System.out.println("No gumball dispensed");
 }
}


 
package stats;

import instances.GumballMachine;
import stateI.State;

public class NoQuarterState implements State {
 GumballMachine gumballMachine;

 public NoQuarterState(GumballMachine gumballMachine){
  this.gumballMachine=gumballMachine;
 }
 
 @Override
 public void insertQuarter() {
  System.out.println("you are insert coin");
  gumballMachine.setState(gumballMachine.getHasQuarterState());
 }

 @Override
 public void ejectQuarter() {
  System.out.println("please insert coin");
 }

 @Override
 public void turnCrank() {
  System.out.println("please insert coin");
 }

 @Override
 public void dispense() {
  System.out.println("please insert coin");
 }
}


 
package stats;

import instances.GumballMachine;
import stateI.State;

public class SoldOutState implements State {
 transient GumballMachine gumballMachine;
 
 public SoldOutState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
 
 @Override
 public void insertQuarter() {
  // TODO Auto-generated method stub
   System.out.println("You can't insert a quarter, the machine is sold out");
 }

 @Override
 public void ejectQuarter() {
  // TODO Auto-generated method stub
  System.out.println("You can't eject, you haven't inserted a quarter yet");
 }

 @Override
 public void turnCrank() {
  // TODO Auto-generated method stub
   System.out.println("You turned, but there are no gumballs");
 }

 @Override
 public void dispense() {
  // TODO Auto-generated method stub
  System.out.println("No gumball dispensed");
 }
}


 
package stats;

import instances.GumballMachine;
import stateI.State;

public class SoldState implements State{
 transient GumballMachine gumballMachine;
 
 public SoldState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
 
 @Override
 public void insertQuarter() {
  // TODO Auto-generated method stub
  System.out.println("this give you egg ....ing");
 }

 @Override
 public void ejectQuarter() {
  // TODO Auto-generated method stub
  System.out.println("you alrealy take it");
 }

 @Override
 public void turnCrank() {
  // TODO Auto-generated method stub
  System.out.println("try only one!");
 }

 @Override
 public void dispense() {
  gumballMachine.releaseBall();
  if(gumballMachine.getCount()>0){
   gumballMachine.setState(gumballMachine.getNoQuarterState());
  }else{
   System.out.println("Opps , out of gumballs");
   gumballMachine.setState(gumballMachine.getSoldState());
  }
 }
}


  3) state를 이용해 이를 구현한 구현체 

 
package instances;

import stateI.State;
import stats.HasQuarterState;
import stats.NoQuarterState;
import stats.SoldOutState;
import stats.SoldState;

public class GumballMachine {

 State soldOutState;
 State noQuarterState;
 State hasQuarterState;
 State soldState;
 
 State state = soldOutState;
 
 int count =0;
 
 public GumballMachine(int numberGumballs){
  soldOutState = new SoldOutState(this);
  noQuarterState = new NoQuarterState(this);
  hasQuarterState = new HasQuarterState(this);
  soldState = new SoldState(this);
  
  this.count =numberGumballs;
  
  if(numberGumballs>0){
   state = noQuarterState;
  }
 }
 
 public void insertQuarter(){
  state.insertQuarter();
 }
 
 public void ejectQuarter(){
  state.ejectQuarter();
 }
 
 public void turnCrank(){
  state.turnCrank();
  state.dispense();
 }
 
 public void setState(State state) {
  this.state=state;
 }
 
 public void releaseBall(){
  System.out.println("A gumball comes rolling out the slot...");
  if(count!=0){
   count=count -1;
  }
 }

 public void refill(int count) {
  this.count = count;
  state = noQuarterState;
 }

 public int getCount() {
        return count;
    }
 
 public State getState(){
  return state;
 }
 
 public State getSoldOutState(){
  return getSoldOutState();
 }
 
 public State getNoQuarterState() {
        return noQuarterState;
    }
 
 public State getHasQuarterState() {
        return hasQuarterState;
    }
 
 public State getSoldState() {
        return soldState;
    }
 
  public String toString() {
         StringBuffer result = new StringBuffer();
         result.append("\nMighty Gumball, Inc.");
         result.append("\nJava-enabled Standing Gumball Model #2004");
         result.append("\nInventory: " + count + " gumball");
         if (count != 1) {
             result.append("s");
         }
         result.append("\n");
         result.append("Machine is " + state + "\n");
         return result.toString();
     }
}


  4) 이를 테스트 하기 위한 코드
 
package tsstmain;

import instances.GumballMachine;

public class GumballMachineTestDrive {
 public static void main(String[] args) {
  GumballMachine gumballMachine = new GumballMachine(5);
  System.out.println(gumballMachine);
  
  gumballMachine.insertQuarter();
  gumballMachine.turnCrank();
  
  System.out.println(gumballMachine);
  
  gumballMachine.insertQuarter();
  gumballMachine.turnCrank();
  gumballMachine.insertQuarter();
  gumballMachine.turnCrank();
  
  System.out.println(gumballMachine);
 }
}


결과 : 

Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 5 gumballs
Machine is stats.NoQuarterState@2d11f5f1

you are insert coin
You turned...
A gumball comes rolling out the slot...

Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 4 gumballs
Machine is stats.NoQuarterState@2d11f5f1

you are insert coin
You turned...
A gumball comes rolling out the slot...
you are insert coin
You turned...
A gumball comes rolling out the slot...

Mighty Gumball, Inc.
Java-enabled Standing Gumball Model #2004
Inventory: 2 gumballs
Machine is stats.NoQuarterState@2d11f5f1



2. 다이어그램

  3) 다이어그램
      역시 하단 링크를 참고바랍니다.
      하단 링크에서도 자세하게 설명하고 있습니다.
      state 및 이를 implements 한 구현체 클래스는 스트리티지
      패턴과 비슷하나 이를 밖에서 조합하여
      쓰는 과정에서 약간 차이가 있음.

   http://hongjinhyeon.tistory.com/50


댓글 없음:

댓글 쓰기