CS_Step14 - 상태 패턴(State Pattern)

장선웅·2022년 7월 27일
0

상태 패턴이란?

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

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


1. 상태 패턴은 왜 사용할까?

예를 들어, 차(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버튼 하나로 차의 상태를 더 많이 바꿀 수 있게 된다면(그럴일은 없겠지만), 코드가 굉장히 길어지게 되고, 상태에 따라 하고자 하는 행위를 파악하기 쉽지 않을 것이다.


3. 상태 패턴 구현 방법

  1. Car의 상태를 캡슐화한 인터페이스 선언
interface CarState{
	//power 버튼을 누르는 메서드 선언
	public void powerPush();
}
  1. 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("대기 모드");
    }
}
  1. 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();
    }
}
  1. 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

4. 상태 패턴의 장/단점

장점

  1. 하나의 객체에 대한 여러 동작(상태)을 구형해야 할 때 상태 객체만 수정하므로 동작의 추가, 삭제가 용이해진다.
  2. 객체의 상태에 따른 조건문이 줄어든다 => 코드가 간결해지고 가독성이 높이진다.

단점

  1. 상태 객체가 증가한다 => 관리해야할 클래스가 많아진다.
profile
개발을 꿈꾸는 초짜

0개의 댓글