[GOF] 스테이트 패턴으로 슈팅게임 만들기 🔫
먼저 스테이트 패턴의 "스테이트"가 뭔지 알아봅시다.
스테이트 패턴을 이용하면, 여러 상태에 따라 기능을 손쉽게 변경할 수 있습니다!
상태가 뭘까요?
상태가 뭘까 🤔
저같은 경우에,
배가 고픈 "상태"면 밥을 먹어야 합니다.
졸린 "상태"라면 낮잠을 좀 자야됩니다.
화가 난 "상태"라면 무언가를 때려 부숴야 합니다. ❤
객체 지향 시스템을 이루고 있는 객체들도 각각 자신만의 상태를 갖고 있습니다.
그리고 저처럼, 객체들도 자신의 상태에 따라 다른 행위를 할 때도 있습니다.
슈팅 게임 캐릭터를 만들어보자! 🔫
혹시 카운터 스트라이크라는 슈팅 게임을 아시나요?
저는 1.6버전 때부터 카운터 스트라이크를 즐겼습니다.
게이머는 원하는 총기를 구입한 뒤,
적군을 구입한 총기로 쓰러뜨려야 합니다.
총기는 각각 장단점이 있기 때문에, 상황에 따라 필요한 총기를 구매하는 것이 좋습니다.
게임 얘기는 여기까지만 하고,
바로 우리가 조종할 캐릭터를 클래스로 만들어 봅시다!
먼저, 총을 쏘려면 총이 있어야 겠죠?
enum 으로 총을 만들어 봅시다.
enum Weapon {
PISTOL, M4A1, AWP
}
이제 우리가 조종할 캐릭터를 클래스로 만들어 봅시다.
class Soldier {
// 캐릭터가 현재 소지한 총기 (상태)
private Weapon weapon;
// 캐릭터는 권총 (pistol)을 기본으로 가집니다.
public Soldier() {
this.weapon = Weapon.PISTOL;
}
// 캐릭터의 총기 (상태)를 바꿉니다. (
void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
// 현재 총기(상태)에 따라 다른 공격을 합니다.
void attack() {
switch (this.weapon) {
case PISTOL:
System.out.println("핑.. 핑.. 핑..");
break;
case M4A1:
System.out.println("둥둥둥둥 둥둥둥둥");
break;
case AK47:
System.out.println("탕! 탕! 탕! 탕!");
break;
case AWP:
System.out.println("철컥, 쉭 펑~!");
break;
}
}
}
이렇게 현재 갖고있는 총기(상태) 에 따라 다르게 공격할 수 있는 캐릭터를 만들었습니다!
그런데, 산탄총을 하나 더 추가하고 싶습니다.
근거리에서 매우 강력하기 때문이죠.
산탄총을 추가하려면 코드를 어떻게 바꿔야 할까요?
잠깐 생각해봅시다....
먼저, 총기 목록에 샷건을 추가해줍니다.
enum Weapon {
PISTOL, // 권총
M4A1, // 소총
AWP, // 저격총
SHOTGUN // 샷건
}
그리고 게임 캐릭터의 공격 기능을 다음과 같이 변경합니다.
void attack() {
switch (this.weapon) {
case PISTOL:
System.out.println("핑.. 핑.. 핑..");
break;
case M4A1:
System.out.println("둥둥둥둥 둥둥둥둥");
break;
case AWP:
System.out.println("철컥, 쉭 펑~!");
break;
case SHOTGUN: // 추가된 부분
System.out.println("철컥, 팡! 철컥, 팡!");
break;
}
}
추가로 기관총도 추가하고 싶다면 또 같은 작업을 반복해야 합니다.
너무 여러곳을 변경해야하고,
또 변경할 부분이 애매모호해서, 변경할 부분을 찾는 것도 번거롭습니다.
스테이트 패턴을 이용해 개선시켜봅시다!
스테이트 패턴 적용하기 🎈
스테이트 패턴은 상태를 클래스로 구현하여 메서드를 상태 클래스에 위임시킵니다.
우리는 각 총기를 클래스로 만들고,
그 클래스에 공격 기능을 구현할 것입니다.
그리고 게임 캐릭터가 공격할때,
자신이 갖고 있는 총기 클래스의 객체에 공격 기능을 위임할 것입니다.
무슨 말인지 잘 이해가 되지 않으실 것 같습니다.
코드로 직접 작성해 봅시다!
먼저 게임 캐릭터의 상태를 위한 인터페이스를 만듭니다.
interface Weapon {
void attack();
}
그리고 이 인터페이스를 구현해 각 총기의 클래스를 만듭니다.
class PISTOL implements Weapon {
public void attack() {
System.out.println("핑.. 핑.. 핑..");
}
}
class M4A1 implements Weapon {
public void attack() {
System.out.println("둥둥둥둥 둥둥둥둥");
}
}
class AWP implements Weapon {
public void attack() {
System.out.println("철컥, 쉭 펑~!");
}
}
이제 게임 캐릭터 클래스를 다음과 같이 변경시킵니다.
class Soldier {
private Weapon weapon;
public Soldier() {
this.weapon = new PISTOL();
}
void setWeapon(Weapon weapon) {
this.weapon = weapon;
}
void attack() {
this.weapon.attack(); // 총기 클래스에 공격 기능 위임
}
}
게임 캐릭터 클래스가 매우 깔끔해졌고,
이제 총기(상태)를 추가하는 것도 매우 쉬워졌습니다.
그냥 Weapon 인터페이스를 구현한 클래스만 하나 더 만들면 됩니다!
이렇게 스테이트 패턴을 사용하면
객체가 상태에 따라 다르게 행동하도록 할 수 있습니다.
감사합니다.