본문 바로가기

코딩/Software Architecture

[GoF Design Pattern] State

* State Pattern

State Pattern : 어떤 상태를 클래스로 표현해 객체로 다룰 수 있는 패턴.

많은 상태가 있고 각 상태마다 다양한 처리를 해야 하는 경우 if 조건문이 많아지는데, 이를 효과적으로 줄여주는 패턴.

4개의 상태가 있고, 상태를 변화시킬 때마다 출력하는 문구가 다른 경우 총 16개의 if 조건문을 사용해 각 상태 변화에 따른 출력 문구를 정해야 한다.

이때 State Pattern을 사용하면 4개의 State 객체를 생성해 이를 처리할 수 있다.

Player : 4가지 상태를 필드에 가질 수 있음. 이를 통해 자신의 상태를 정할 수 있음.

State : 각 상태를 하나로 묶는 추상 클래스. 

StandUpState, SitDownState, WalkState, RunState : 각 이름의 상태를 구현한 클래스.

상태를 가지고 있는 Player

public class Player {
    private int speed;
    
    public void setSpeed(int speed) {
    	this.speed = speed;
    }
    
    public int getSpeed() {
    	return speed;
    }
    
    private State state = new StandUpState(this); // 현재 상태
    
    public void setState(State state) {
    	this.state = state;
     }
     
     public State getState() {
     	return state;
    }
    
    public void talk(Steing msg) {
    	System.out.println("플레이어의 말: \"" + msg + "\"");
    }
}

State 인터페이스

public abstract class State {
    protected Player player;
    
    public State(Player player) {
    	this.player = player;
    }
    
    public abstract void standUp();
    public abstract void sitDown();
    public abstract void walk();
    public abstract void run();
    public abstract void getDescription();
}

각 상태들 구현

- StandUpState

public class StandUpState extend State {

    public StandUpState(Player player) {
    	super(player);
    }
    
    @Override
    public void standUp() {
    	player.talk("언제 움직일꺼야?");
    }
    
    @Override
    public void sitDown() {
    	player.setState(new SitDownState(player));
        player.talk("앉으니깐 편하고 좋습니다.");
    }
    
    @Override
    public void walk() {
    	player.setSpeed(5);
        player.setState(new WalkState(player));
        player.talk("걷기는 제2의 생각하기다..");
    }
    
    @Override
    public void run() {
    	player.setSpeed(10);
        player.setState(new ReunState(player));
        player.talk("갑자기 뛴다!");
    }
    
    @Override
    public String getDescription() {
    	return "제자리에 서 있음";
    }
        
}

- SitDownState

public class SitDownState extend State {

    public SitDownState(Player player) {
    	super(player);
    }
    
    @Override
    public void standUp() {
        player.setState(new StandUpState(player));
        player.talk("인나자..");
    }
    
    @Override
    public void sitDown() {
        player.talk("쥐나겠다..");
    }
    
    @Override
    public void walk() {
        player.setState(new StandUpState(player));
        player.talk("앉아서 어떻게 걸어? 일단 서자..");
    }
    
    @Override
    public void run() {
        player.setState(new StandUpState(player));
        player.talk("앉아서 어떻게 뛰어? 일단 서자..");
    }
    
    @Override
    public String getDescription() {
    	return "앉아있음";
    }
        
}

- WalkState

public class WalkState extend State {

    public WalkState(Player player) {
    	super(player);
    }
    
    @Override
    public void standUp() {
        player.setSpeed(0);
    	player.talk("멈춰...");
        player.setState(new StandUpState(player));
    }
    
    @Override
    public void sitDown() {
        player.setSpeed(0);
        player.talk("걷다가 앉으면 넘어질 수 있어요..");
        player.setState(new SitDownState(player));
    }
    
    @Override
    public void walk() {
        player.talk("난 걷는걸 좋아하지..");
    }
    
    @Override
    public void run() {
    	player.setSpeed(20);
        player.talk("걷다가 뛰면 열라 빨리 뛸 수 있지!");
        player.setState(new ReunState(player));
    }
    
    @Override
    public String getDescription() {
    	return "걷는 중";
    }
        
}

- RunState

public class RunState extend State {

    public RunState(Player player) {
    	super(player);
    }
    
    @Override
    public void standUp() {
        player.setSpeed(0);
    	player.talk("뛰다가 갑자기 서면 무릎 연골 나가요...");
        player.setState(new StandUpState(player));
    }
    
    @Override
    public void sitDown() {
        player.setSpeed(0);
        player.talk("뛰가다 앉으라고???");
        player.setState(new StandUpState(player));
    }
    
    @Override
    public void walk() {
        player.setSpeed(8);
        player.talk("속도를 줄일꼐요~");
        player.setState(new WalkState(player));
    }
    
    @Override
    public void run() {
    	player.setSpeed(player.getSpeed() + 2);
        player.talk("더 빨리 뛰라는 얘기지?");
    }
    
    @Override
    public String getDescription() {
    	return "뛰는 중";
    }
        
}

지금까지 작성한 클래스 활용하기.

 

public class MainEntry {
    public static void main(String[] args) {
    	plater plater = new Player();
        Scanner scanner = new Scanner(System.in);
        
        while(true) {
        	System.out.println("플레이어의 상태: "
            + player.getState().getDescription()
            + " / 속도: " + player.getSpeed() + "km/h");
            
            System.out.print("[1]제자리 서기, [2]앉기, [3]걷기, [4]뛰기, [5]종료: ");
            
            String input = scanner.next();
            System.out.println();
            
            if(input.equals("1")) player.getState().standUp();
            else if(input.equals("2")) player.getState().sitDown();
            else if(input.equals("3")) player.getState().walk();
            else if(input.equals("4")) player.getState().run();
            else if(input.equals("5")) break;
        }
        scanner.close();
    }
}