카테고리 없음

20250423 TIL 팩토리 패턴

note4973 2025. 4. 23. 21:27

TIL: 팩토리 패턴 (Factory Pattern)

 

 팩토리 패턴이란?

객체 생성을 new 키워드로 직접 하지 않고, 전용 클래스(Factory) 가 대신 생성해주는 디자인 패턴.

생성 로직을 하나의 장소로 집중시켜서, 유지보수, 확장성, 유닛 테스트 등에 유리하다.

상황문제팩토리 패턴으로 해결

new가 여기저기 흩어져 있음 결합도 증가 Factory 하나로 통합
생성 조건이 다양함 코드 중복, 혼란 내부에서 조건 분기 처리
다양한 하위 클래스 필요 타입 의존성 증가 추상 클래스/인터페이스로 통일
public enum EnemyType { Goblin, Orc }

public class Enemy { }
public class Goblin : Enemy { }
public class Orc : Enemy { }

public static class EnemyFactory
{
    public static Enemy CreateEnemy(EnemyType type)
    {
        switch (type)
        {
            case EnemyType.Goblin: return new Goblin();
            case EnemyType.Orc: return new Orc();
            default: throw new ArgumentOutOfRangeException();
        }
    }
}

 

  • 객체 생성을 중앙에서 관리하니 코드가 깔끔하고 유연해졌다.
  • 나중에 적 타입이 추가되더라도 Factory만 수정하면 끝이라 유지보수가 편함.
  • 특히 유니티에서 프리팹 기반으로 적 생성할 때 딱 좋은 패턴이라는 걸 느낌.
public class ObjectPool<T> where T : Component
{
    private Queue<T> pool = new Queue<T>();
    private T prefab;

    public ObjectPool(T prefab, int initialSize)
    {
        this.prefab = prefab;
        for (int i = 0; i < initialSize; i++)
        {
            T obj = GameObject.Instantiate(prefab);
            obj.gameObject.SetActive(false);
            pool.Enqueue(obj);
        }
    }

    public T Get(Vector3 position, Transform parent = null)
    {
        T obj = pool.Count > 0 ? pool.Dequeue() : GameObject.Instantiate(prefab);
        obj.transform.position = position;
        obj.transform.SetParent(parent);
        obj.gameObject.SetActive(true);
        return obj;
    }

    public void ReturnToPool(T obj)
    {
        obj.gameObject.SetActive(false);
        pool.Enqueue(obj);
    }
}

 

public class EnemyFactory : MonoBehaviour
{
    public GameObject goblinPrefab;
    public GameObject orcPrefab;

    private ObjectPool<EnemyStats> goblinPool;
    private ObjectPool<EnemyStats> orcPool;

    private void Awake()
    {
        goblinPool = new ObjectPool<EnemyStats>(goblinPrefab.GetComponent<EnemyStats>(), 10);
        orcPool = new ObjectPool<EnemyStats>(orcPrefab.GetComponent<EnemyStats>(), 10);
    }

    public EnemyStats CreateEnemy(EnemyType type, Vector3 position)
    {
        return type switch
        {
            EnemyType.Goblin => goblinPool.Get(position),
            EnemyType.Orc => orcPool.Get(position),
            _ => null
        };
    }

    public void ReturnEnemy(EnemyStats enemy)
    {
        if (enemy is Goblin) goblinPool.ReturnToPool(enemy);
        else if (enemy is Orc) orcPool.ReturnToPool(enemy);
    }
}

 

팩토리 + 오브젝트 풀 

둘을 동시에 사용시 생성책임은 팩토리에서 관리 재사용을 통한 instantiate 최소화 가능