[디자인패턴] 스테이트패턴(State Pattern)

고지훈·2021년 10월 9일
1

DesignPattern

목록 보기
11/16
post-thumbnail

스테이트패턴(State Pattern)

스테이트 패턴은 객체가 특정 상태에 따라 행위를 달리하는 상황에서 자신이 직접 상태를 체크하여 상태에 따라 행위를 호출하지 않고, 상태를 객체화하여 상태가 행동을 할 수 있도록 위임하는 패턴을 말한다.

즉, 객체의 특정 상태를 클래스로 선언하고, 클래스에서는 해당 상태에서 할 수 있는 행위들을 메서드로 정의한다. 이러한 상태 클래스를 인터페이스로 캡슐화하여 클라이언트에서 인터페이스를 호출하는 방식을 이야기한다.


왜, 스테이트패턴을 사용할까?

스테이트패턴을 구현하기 위한 예로 컴퓨터를 켜고 끄는 상황을 생각해보자.

  • 컴퓨터의 전원이 꺼진 상태에서 전원 버튼을 누르면, 전원을 켤 수 있다.
  • 컴퓨터의 전원이 켜진 상태에서 전원 버튼을 누르면, 전원을 끌 수 있다.

위의 상황을 아래의 코드로 구현할 수 있다.

// Computer.java
public class Computer {
	public static String ON = "ON";
    public static String OFF = "OFF";
    private String powerState = "";
    
    public Computer() {
    	setPowerState(Computer.OFF);
    }
    
    public void setPowerState(String powerState) {
    	this.powerState = powerState;
    }
    
    public void powerPush() {
    	if("ON".equals(this.powerState)) {
        	System.out.println("전원 OFF");
        }else {
        	System.out.println("전원 ON");
        }
    }
}
// Client.java
public class Client {
    public static void main(String args[]){
    	Computer computer = new Computer();
        computer.powerPush();
        computer.setPowerState(Computer.ON);
        computer.powerPush();
    }
}

해당 코드를 실행하면, 컴퓨터가 ON상태이면 OFF상태로 변경하고, OFF상태이면 ON상태로 변경하는 문구가 실행될 것이다.

위의 기능에서 절전모드를 추가해보자! 그럼 다음과 같이 정의할 수 있다.

  • 컴퓨터 전원이 켜진 상태에서 전원버튼을 누르면, 전원을 끌 수 있다.
  • 컴퓨터 전원이 꺼진 상태에서 전원버튼을 누르면, 절전모드로 변경된다.
  • 컴퓨터 절전모드에서 전원버튼을 누르면, 전원을 켤 수 있다.

위의 조건을 코드로 구현하게 되면 아래와 같이 나타낼 수 있다.

// Computer.java
public class Computer {
	public static String ON = "ON";
    public static String OFF = "OFF";
    public static String SAVING = "SAVING";
    private String powerState = "";
    
    public Computer() {
    	setPowerState(Computer.OFF);
    }
    
    public void setPowerState(String powerState) {
    	this.powerState = powerState;
    }
    
    public void powerPush() {
    	if("ON".equals(this.powerState)) {
        	System.out.println("전원 OFF");
        }else if ("SAVING".equals(this.powerState)) {
        	System.out.println("전원 ON");
        }else {
        	System.out.println("절전모드");
        }
    }
}
// Client.java
public class Client {
    public static void main(String args[]){
    	Computer computer = new Computer();
        computer.powerPush();
        computer.setPowerState(Computer.ON);
        computer.powerPush();
        computer.setPowerState(Computer.SAVING);
        computer.powerPush();
        computer.setPowerState(Computer.OFF);
        computer.powerPush();
    }
}

위와 같이 조건을 추가할 경우 조건문의 길이가 굉장히 길어지는 단점이 발생하는것을 알 수 있다. 또한 기능이 변경될 경우, 해당 조건을 일일히 찾아가 변경해야한다는 단점이 있다.


스테이트패턴 구현

위의 단점을 개선하기 위해 스테이트패턴을 적용시켜보자!

스테이트패턴을 적용하면 상태(ON, OFF, SAVING)를 클래스로 정의하고, 이를 하나의 인터페이스로 캡슐화를 한다.

가장 먼저, 전원상태를 캡슐화한 인터페이스 PowerState를 선언한다.

// PowerState.java
public interface PowerState {
	public void powerPush();
}

다음으로 PowerState인터페이스를 구현한 상태 클래스를 정의한다.

// On.java
public class On implements PowerState {
    @Override
    public void powerPush() {
    	System.out.println("전원 OFF");
    }
}
// Off.java
public class Off implements PowerState {
    @Override
    public void powerPush() {
    	System.out.println("절전모드");
    }
}
// Saving.java
public class Saving implements PowerState {
    @Override
    public void powerPush() {
    	System.out.println("전원 ON");
    }
}

다음으로 Computer클래스를 선언한다.

// Computer.java
public class Computer {
    private PowerState powerState;
    
    public Computer() {
    	this.powerState = new Off();
    }
    
    public void setPowerState(PowerState powerState) {
    	this.powerState = powerState;
    }
    
    public void powerPush() {
    	powerState.powerPush();
    }
}

위 코드를 보면 조건을 분기하는 코드는 사라지고 인터페이스의 powerPush()메서드를 호출하는 것을 확인할 수 있다.

// Client.java
public class Client {
    public static void main(String args[]){
    	Computer computer = new Computer();
        On on = new On();
        Off off = new Off();
        Saving saving = new Saving();
        
        computer.powerPush();
        computer.setPowerState(on);
        computer.powerPush();
        computer.setPowerState(saving);
        computer.powerPush();
        computer.setPowerState(off);
        computer.powerPush();
    }
}

위 코드의 결과는 이전과 동일하다. 조건문 대신 객체의 상태를 클래스로 선언하고, 해당 상태에서 수행할 수 있는 동작을 수행하는 것을 확인할 수 있다.

스테이트패턴 학습 시 참고 블로그: https://victorydntmd.tistory.com/294?category=719467

profile
"계획에 따르기보다 변화에 대응하기를"

0개의 댓글