객체의 상태가 바뀜에 따라서 상태를 정의한 클래스의 메소드를 통해
객체의 행동과 상태를 바꿀 수 있는 디자인 패턴
pulic interface CarState {
public void startButton(); // 시동 버튼 누르기
public void accel(); // 엑셀 밟기
public void breaking(); // 정지
}
상태패턴의 예시를 자동차의 각 상태에 따른 메소드 들의 변화를 통해 설명하려고 할 때
자동차의 상태에 따른 행동들에 대해 캡슐화한 인터페이스가 위와 같다.
public class OffState implements CarState {
Car car;
public OffState(Car car) {
this.car = car;
}
public void startButton() {
System.out.println("시동을 켭니다");
this.car.setState(this.car.Parking);
}
public void accel() {
System.out.println("시동 꺼짐 상태에서는 엑셀이 작동하지 않습니다");
}
public void breaking() {
System.out.println("브레이크가 작동합니다");
}
}
시동 꺼짐 상태에 대한 상태 클래스 구현
public class Parking implements CarState {
Car car;
public Parking(Car car) {
this.car = car;
}
public void startButton() {
System.out.println("시동을 끕니다");
this.car.setState(this.car.OffState);
}
public void accel() {
System.out.println("주차브레이크 모드 중 차가 앞으로 나가지 않습니다.");
}
public void breaking() {
System.out.println("브레이크가 작동합니다");
}
}
Parking(주차) 상태에 대한 상태 클래스 구현
public class Drive implements CarState {
Car car;
public Drive(Car car) {
this.car = car;
}
public void startButton() {
System.out.println("주행 중에는 시동을 끌 수 없습니다");
}
public void accel() {
System.out.println("전진 가속 합니다");
}
public void breaking() {
System.out.println("브레이크를 밟아 속도를 줄입니다");
}
}
Drive(주행) 상태에 대한 상태 클래스 구현
public class Rear implements CarState {
Car car;
public Rear(Car car) {
this.car = car;
}
public void startButton() {
System.out.println("후진 중에는 시동을 끌 수 없습니다");
}
public void accel() {
System.out.println("후진 가속 합니다");
}
public void breaking() {
System.out.println("브레이크를 밟아 속도를 줄입니다");
}
}
Rear(후진주행) 상태에 대한 상태 클래스 구현
위와 같이 자동차는 4개의 상태에 따라서 엑셀을 밟거나 브레이크를 밟거나
스타트버튼을 눌렀을 때 동작하는 경우가 다르다.
이제 이 상태들을 가지고 Car 클래스를 구현해보면
public class Car {
CarState OffState;
CarState Parking;
CarState Drive;
CarState Rear;
CarState state;
public Car() {
this.offState = new OffState(this);
this.Parking = new Parking(this);
this.Drive = new Drive(this);
this.Rear = new Rear(this);
this.state = this.offState;
}
public void startButton() {
this.state.startButton();
}
public void accel() {
this.state.accel();
}
public void breaking() {
this.state.breaking();
}
}
이렇게 상태 클래스에 행위를 위임하면서 동작과 그에 따른 상태를 변경할 수 있는 것이 상태패턴이다.
(최대한 간단하게 예시를 들기 위해서 간단한 동작들만 구현하였음.)
메소드 동작을 캡슐화한 인터페이스를 구현한 클래스에게
행위를 위임시키는 방법은 전략패턴에서도 확인할 수 있었다.
그렇다면 이 둘의 차이점은 과연 무엇일까?
상태패턴은 상태 변화에 외부 개입이 필요가 없다.
전략패턴은 상태 변화에 외부 개입이 필요하다.
상태패턴은 스스로 State를 바꿀 수 있지만, 전략패턴은 사용자의 입력이 필요하다.
상태패턴은 위 예시에서 OffState 클래스와 Parking에서의 startButton() 메소드를 보면 상태클래스 안에서 자동적으로 상태를 변화시켜주는 것을 확인할 수 있다.
하지만 전략패턴에서는 클라이언트에서 어떤 전략클래스를 사용할지를 정해주어야 한다.