FPS와 같은 슈팅게임을 만든다고 가정하자. 아마도 수 많은 종류의 무기들이 있을 것이다. 권총, 라이플, 근접무기, 투척무기 등등… 그렇다면 이들의 구현은 어떻게 하면 좋을까? 가장 쉬운 방법은 Update()
문에 하나 하나 모두 구현하는 것이다. 하지만 다음과 같은 문제가 발생한다.
swith(weapon){
case HandGun:
// 권총을 위한 구현
// 무기 교체, 애니메이션, 사운드, 총알 변경 등등
break;
case RifileGun:
// 라이플을 위한 구현
break;
case SniperGun:
// 저격총을 위한 구현
break;
}
다른 무기들이 추가될 때마다 이렇게 번거로운 과정을 거쳐야 한다. 무기의 종류가 이렇게 적은 수량이라면 문제가 되지 않을수도 있지만, 대규모 업데이트를 통해서 100개 가량의 신규 무기들이 추가된다면? 아마 반드시 빼먹는 부분이 있을 것이고, 이로 인해서 오류가 발생할 것이다.
여러 알고리즘을 하나의 추상적인 접근점(인터페이스 or 추상클래스)을 통해서 서로 교환이 가능하도록 하는 패턴이다. 위의 상황을 Strategy Pattern을 통해서 해결할 수 있다.
//IWeapon.cs
public interface IWeapon
{
public void Attack() {}
}
//Gun.cs
public class Gun : IWeapon
{
public void Attack()
{
Debug.Log("Gun Fired");
}
}
//Sword.cs
public class Sword : IWeapon
{
public void Attack()
{
Debug.Log("Sword Swing");
}
}
이와 같이 IWeapon
인터페이스를 통해서 전반적인 무기의 기능을 구현하고, 이를 상속시켜서 사용하면 된다. 이를 실제로 사용하는 코드는 아래와 같다.
public class Player : MonoBehaviour
{
public IWeapon currWeapon;
void Start()
{
currWeapon = new Sword();
}
void Update()
{
Swap();
Attack();
}
void Attack()
{
if (Input.GetMouseButtonDown(0))
{
currWeapon.Attack();
}
}
void Swap()
{
if (Input.GetKeyDown(KeyCode.Alpha1) && !(currWeapon is Sword))
{
currWeapon = new Sword();
Debug.Log("Switched to Sword");
}
if (Input.GetKeyDown(KeyCode.Alpha2) && !(currWeapon is Gun))
{
currWeapon = new Gun();
Debug.Log("Switched to Gun");
}
}
}