상태 패턴이란?
- 상태 패턴은 객체가 특정 상태에 따라 행위를 달리하는 상황에서, 자신이 직접 상태를 체크하여 상태에 따라 행위를 호출하지 않고, 상태를 객체화 하여 상태가 행동을 할 수 있도록 하는 패턴이다.
다시 말해, 객체의 특정 상태를 클래스로 선언하고, 클래스에서는 해당 상태에서 할 수 있는 행위들을 메서드로 정의한다. 그리고 이러한 각 상태 클래스들을 인터페이스로 캡슐화하여, 클라이언트에서 인퍼에스르를 호출하는 방식의 패턴이다.
예를 들어, 차(Car)의 시동을 켜고 끄는 상황을 코드로 작성해 보도록 하자.
//Car 클래스 class Car { //Car의 시동을 키고 끄는 변수는 변하지 않는 변수 static으로 선언 public static String ON = "on"; public static String OFF = "off"; //Car의 상태를 담을 변수 private String carState = ""; //Car생성자 public Car() { //Car의 상태를 OFF로 설정 setCarState(Car.OFF); } //상태를 set할 메서드 선언 public void setCarState(String carState) { this.carState = carState; } //조건문을 통한 Car의 state 지정(powerPush를 통해 "on"이면 "off", "off"이면 "on"으로 바뀜) public void powerPush() { if("on".equals(this.carState)) { System.out.println("시동 off"); } else { System.out.println("시동 on"); } } } //Client클래스 (main) public class Client { public static void main(String[] args) { //Car객체 생성 Car car = new Car(); //초기 Car의 상태는 OFF인데 그 상태에서 power버튼을 누른다. car.powerPush(); //Car의 상태를 ON으로 설정 car.setCarState(Car.ON); //그 상태에서 power버튼을 누른다 car.powerPush(); } } //결과값 시동 off
이러한 상황에서 예시를 하나 추가해 보도록하자.
이 조건을 가지고 다시 코드를 작성해 보도록 하자.
//Car 클래스 class Car { //Car의 시동을 키고 끄는 변수는 변하지 않는 변수 static으로 선언 public static String ON = "on"; public static String OFF = "off"; public static String STANDY_MODE = "standy mode"; //Car의 상태를 담을 변수 private String carState = ""; //Car생성자 public Car() { //Car의 상태를 OFF로 설정 setCarState(Car.OFF); } //상태를 set할 메서드 선언 public void setCarState(String carState) { this.carState = carState; } public void powerPush() { if("on".equals(this.carState)) { System.out.println("시동 off"); }else if("off".equals(this.carState)) { System.out.println("대기 모드"); } else { System.out.println("시동 on"); } } } //Client클래스 (main) public class Client { public static void main(String[] args) { //Car객체 생성 Car car = new Car(); //초기 Car의 상태는 OFF인데 그 상태에서 power버튼을 누른다. car.powerPush(); //Car의 상태를 ON으로 설정 car.setCarState(Car.ON); //그 상태에서 power버튼을 누른다 car.powerPush(); //Car의 상태를 OFF로 설정 car.setCarState(Car.OFF); //그 상태에서 power버튼을 누른다. car.powerPush(); //Car의 상태를 STANDY_MODE로 설정 car.setCarState(Car.STANDY_MODE); //그 상태에서 power버튼을 누른다 car.powerPush(); } } //결과값 대기 모드 시동 off 대기 모드 시동 on
물론 위 코드를 살펴본다면, 조건문 하나만 추가되었음으로 그리 문제가 되지는 않는다.
만약에 power버튼 하나로 차의 상태를 더 많이 바꿀 수 있게 된다면(그럴일은 없겠지만), 코드가 굉장히 길어지게 되고, 상태에 따라 하고자 하는 행위를 파악하기 쉽지 않을 것이다.
- Car의 상태를 캡슐화한 인터페이스 선언
interface CarState{ //power 버튼을 누르는 메서드 선언 public void powerPush(); }
- CarState 인터페이스를 구현한 각 상태 클래스 생성
//시동을 켜는 클래스 class On implements CarState { public void powerPush() { System.out.println("시동 on"); } } //시동을 끄는 클래스 class Off implements CarState { public void powerPush() { System.out.println("시동 off"); } } //대기모드로 바뀌는 클래스 class Standy_Mode implements CarState { public void powerPush() { System.out.println("대기 모드"); } }
- Car 클래스 정의
class Car { private CarState carState; //Car 생성자 public Car() { //초기 상태를 Off로 설정 this.carState = new Off(); } //Car의 상태를 set하는 메서드 public void setCarState(CarState carState) { this.carState = carState; } //power버튼을 누르는 메서드 public void powerPush() { carState.powerPush(); } }
- Client클래스 (main)
public class Client { public static void main(String[] args) { //Car객체 생성 Car car = new Car(); //Car의 각 상태의 객체 생성 On on = new On(); Off off = new Off(); Standy_Mode standy_Mode = new Standy_Mode(); //Car의 상태 지정 초기 상태는 OFF //그 상태에서 power버튼 누르기 car.powerPush(); //Car의 상태를 on으로 car.setCarState(on); //그 상태에서 power버튼 누르기 car.powerPush(); //Car의 상태를 Standy_Mode로 car.setCarState(standy_Mode); //그 상태에서 power버튼 누르기 car.powerPush(); //Car의 상태를 OFF로 car.setCarState(off); //그 상태에서 power버튼 누르기 car.powerPush(); } } //결과값 시동 off 시동 on 대기 모드 시동 off
장점
- 하나의 객체에 대한 여러 동작(상태)을 구형해야 할 때 상태 객체만 수정하므로 동작의 추가, 삭제가 용이해진다.
- 객체의 상태에 따른 조건문이 줄어든다 => 코드가 간결해지고 가독성이 높이진다.
단점
- 상태 객체가 증가한다 => 관리해야할 클래스가 많아진다.