dev/🧩 디자인패턴
상태 패턴이란? (State Pattern)
wugawuga
2022. 12. 31. 23:56
상태 패턴이란?
행위 패턴 중 하나
상태를 객체화 한 패턴
객체의 내부 상태가 바뀜에 따라서 행위를 변경하는 패턴
패턴 적용 전
먼저 "1. 걷기 2. 뛰기 3. 종료" 이런 기능의 프로그램이 있다고 가정하자
String command = "";
while(command.equals("3"){
command = scannser.nextLine();
if (command.equals("1")) {
if (!player.getState().equals("걷기") && !player.getState().equals("앉아있기")) {
player.setState("걷기");
}
} else if (command.equals("2")) {
if (!player.getState().equals("뛰기") && !player.getState().equals("앉아있기")) {
player.setState("뛰기");
}
}
}
억지스럽지만 아주 간단하게 이렇게 분기를 할 수 있다. 더 많은 요구사항이 생기게 된다면 이 분기는 어마어마하게 커질 것이다.
이때 적용할 수 있는 패턴은 상태 패턴이다
패턴 적용 후
public abstract class State {
protected Player player;
public State(Player player) {
this.player = player;
}
abstract void standUp();
abstract void sitDown();
abstract void walk();
abstract void run();
abstract String getDescription();
}
public class WalkState extends State {
public WalkState(Player player) {
super(player);
}
@Override
void standUp() {
player.setSpeed(0);
player.talk("멈춰");
player.setState(new StandUpState(player));
}
@Override
void sitDown() {
player.setSpeed(0);
player.talk("걷다가 앉으면 넘어질 수 있어요");
player.setState(new SitDownState(player));
}
@Override
void walk() {
player.talk("걷는게 좋아");
}
@Override
void run() {
player.setSpeed(20);
player.talk("걷다가 뛰면 빨리 뛸 수 있지");
player.setState(new RunState(player));
}
@Override
String getDescription() {
return "걷는 중";
}
}
public class StandUpState extends State {
public StandUpState(Player player) {
super(player);
}
@Override
void standUp() {
player.talk("언제 움직여?");
}
@Override
void sitDown() {
player.setState(new SitDownState(player));
player.talk("앉으니까 편해요");
}
@Override
void walk() {
player.setSpeed(5);
player.setState(new WalkState(player));
player.talk("걷기는 아주 좋아요");
}
@Override
void run() {
player.setSpeed(10);
player.setState(new RunState(player));
player.talk("뛰니까 힘들어");
}
@Override
String getDescription() {
return "제자리에 서 있어요";
}
}
public class RunState extends State {
public RunState(Player player) {
super(player);
}
@Override
void standUp() {
player.talk("뛰다가 서면 다쳐");
player.setSpeed(0);
player.setState(new StandUpState(player));
}
@Override
void sitDown() {
player.talk("뛰다가 앉으라고?");
player.setSpeed(0);
player.setState(new StandUpState(player));
}
@Override
void walk() {
player.talk("속도를 줄일게요");
player.setSpeed(8);
player.setState(new WalkState(player));
}
@Override
void run() {
player.talk("더 빨리 뛰라는 얘기지?");
player.setSpeed(player.getSpeed() + 2);
}
@Override
String getDescription() {
return "뛰는 중";
}
}
public class SitDownState extends State {
public SitDownState(Player player) {
super(player);
}
@Override
void standUp() {
player.setState(new StandUpState(player));
player.talk("일어나자");
}
@Override
void sitDown() {
player.talk("계속 앉아있네");
}
@Override
void walk() {
player.talk("앉아서 못 걸으니 일단 서자");
player.setState(new StandUpState(player));
}
@Override
void run() {
player.talk("앉아서 못 뛰니 일단 서자");
player.setState(new RunState(player));
}
@Override
String getDescription() {
return "앉아있음";
}
}
그래서 상태 패턴을 언제 사용할까
다중 분기 조건이 너무 많을 때 ❗️❗️❗️
장점
- 상태에 따른 행동을 축소시키고 서로 다른 상태에 대한 행동을 별도의 객체로 관리
- 새로운 상태가 추가되더라도 context 코드 영향이 적다 (context 코드는 위에선 player)
단점
- 상태 클래스들이 많아질수록 변경 규칙을 쉽게 파악하기가 어렵다
- 상태끼리 의존도가 발생할 수도 있다
상태 패턴과 전략 패턴의 차이
두 패턴은 너무나도 비슷하게 생겼다. 디자인 패턴을 공부해보면 대부분 많이 비슷한 것 같다.
상태 패턴은 상태 객체 내부에서 다음 상태를 결정
전략 패턴은 클라이언트에서 다음에 실행할 객체를 지정할 수 있다
즉, 로직이 수행되면서 행동 또는 상태의 변화가 외부의 개입이 필요한지, 특정 구현 클래스에서 알아서 하는지가 중요하다