유니티 팩토리패턴에 대해 알아보자! #Factory 패턴

 

 

유니티 팩토리 패턴에 대해서 #UML 작성해보기

팩토리 패턴은 객체 생성을 담당하는 팩토리 클래스를 도입하여 객체 생성 로직을 캡슐화하는 디자인 패턴입니다. 팩토리  패턴을 사용하면 객체를 생성하는 코드를 분리하여 유연성을 높이고

wlsdn629.tistory.com

예전에 팩토리패턴에 대해 작성했었습니다. 따라서 팩토리 패턴의 정의에 대해서는 언급하지는 않겠습니다.

제가 학교 팀플에서 2D 로그라이크 장르의 게임을 만들고 있는데, 거기에 사용할 만한 Enemy Factory를 한 번 제작해보겠습니다.


IEnemy 인터페이스 정의

public interface IEnemy
{
    void Spawn();
}

먼저, 모든 Enemy 클래스가 구현할 IEnemy 인터페이스를 정의합니다. 각 Enemy는 Spawn이라는 메서드를 갖게 되어 소환 시 특정한 동작을 수행할 수 있습니다.


Enemy 클래스 정의

public class Zombie : IEnemy
{
    public void Spawn()
    {
        Debug.Log("Zombie has spawned!");
    }
}

public class Goblin : IEnemy
{
    public void Spawn()
    {
        Debug.Log("Goblin has spawned!");
    }
}

public class Dragon : IEnemy
{
    public void Spawn()
    {
        Debug.Log("Dragon has spawned!");
    }
}

각 Enemy 유형(Zombie, Goblin, Dragon)은 IEnemy 인터페이스를 구현합니다.


팩토리 클래스 정의 with MonoBehaviour

using UnityEngine;

public class EnemyFactory : MonoBehaviour
{
    public GameObject zombiePrefab;
    public GameObject goblinPrefab;
    public GameObject dragonPrefab;

    public GameObject CreateEnemy(EnemyType type)
    {
        switch (type)
        {
            case EnemyType.Zombie:
                return Instantiate(zombiePrefab);
            case EnemyType.Goblin:
                return Instantiate(goblinPrefab);
            case EnemyType.Dragon:
                return Instantiate(dragonPrefab);
            default:
                throw new System.ArgumentException("Invalid enemy type");
        }
    }
}

팩토리 클래스인 EnemyFactory를 만들어 특정 Enemy을 생성하도록 만들었습니다. 이 클래스는 적의 유형(Type)을 기반으로 Enemy를 생성하는 메서드(CreateEnemy)를 가지고 있습니다. 


팩토리 패턴을 적용한 소환 코드

using UnityEngine;

public class EnemySpawner : MonoBehaviour
{
    public EnemyFactory enemyFactory;

    private void Start()
    {
        SpawnEnemy(EnemyType.Zombie);
        SpawnEnemy(EnemyType.Goblin);
        SpawnEnemy(EnemyType.Dragon);
    }

    public void SpawnEnemy(EnemyType type)
    {
        GameObject enemy = enemyFactory.CreateEnemy(type);
    }
}

EnemySpawner는 Enemy 생성에 필요한 타입 정보만 받고 있습니다. 이 구조는 새로운 Enemy Type을 추가할 때 EnemySpawner코드를 수정하지 않고도 새로운 Enemy을 생성할 수 있습니다.

 

EnemyFactory코드만 수정하면 된다는 뜻이지요.


팩토리 패턴을 적용하지 않았더라면?

using UnityEngine;

public class EnemySpawner : MonoBehaviour
{
    public GameObject zombiePrefab;
    public GameObject goblinPrefab;
    public GameObject dragonPrefab;

    private void Start()
    {
        GameObject zombie = Instantiate(zombiePrefab);
        GameObject goblin = Instantiate(goblinPrefab);
        GameObject dragon = Instantiate(dragonPrefab);
    }

    public void SpawnEnemy(string enemyType)
    {
        switch (enemyType)
        {
            case "Zombie":
                Instantiate(zombiePrefab);
                break;
            case "Goblin":
                Instantiate(goblinPrefab);
                break;
            case "Dragon":
                Instantiate(dragonPrefab);
                break;
            default:
                Debug.LogError("Unknown enemy type");
                break;
        }
    }
}

 

EnemySpawner가 소환과 각 Enemy의 생성에 대한 모든 세부 사항을 직접 관리해야한다는 점을 불편한 사항으로 뽑을 수 있습니다.

위 코드처럼 Type이 3가지 밖에 없는 상황이라면 굳이 팩토리패턴과 같이 복잡하게 구현할 필요는 없지만 Enemy의 Type이 늘어남에 따라 코드 복잡성이 증가하는 상황이라면 팩토리패턴을 사용해서 코드 복잡성을 줄이고 재사용성을 높이는 방법을 택할 수 있습니다.

 

팩토리패턴을 사용함으로써 EnemyFactory는 Enemy를 생성하는 로직만을 담당하고, EnemySpawner는 Enemy의 소환만을 처리함으로 클래스의 책임이 명확해지는 장점도 있습니다.