팩토리 메서드

정선호·2023년 5월 10일
0

Design Patterns

목록 보기
8/24

관련 영상

팩토리 메서드

위키피디아
설명 및 스도코드

  • Factory method는 부모(상위) 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴이며 자식(하위) 클래스가 어떤 객체를 생성할지를 결정하도록 하는 패턴이기도 하다.
  • 부모(상위) 클래스 코드에 구체 클래스 이름을 감추기 위한 방법으로도 사용한다.
  • 팩토리 메서드는 템플릿 메서드의 생성 패턴 버전으로 볼 수 있다.

팩토리 메서드의 구조

  • 제품 인터페이스(Product Interface)
    • 생성자와 자식 클래스들이 생성할 수 있는 모든 객체에 공통
  • 구상 제품(Concrete Product)
    • 제품 인터페이스의 다양한 구현
  • 크리에이터(Creator)
    • 새로운 제품 객체들을 반환하는 팩토리 메서드 선언. 팩토리 메서드의 반환 유형이 제품 인터페이스와 일치해야 함
    • 팩토리 메서드를 추상 클래스로 선언하여 모든 자식 클래스들이 각각 이 메서드의 자체 버전들을 구현하도록 강제하거나, 대안적으로 기초 팩토리 메서드가 디폴트 제품 유형을 반환하도록 만들 수도 있다.
    • 크리에이터의 주책임은 제품 생산이 아니다. 일반적으로 크리에이터 클래스에는 이미 제품과 관련된 핵심 비즈니스 로직이 있고 팩토리 메서드는 이 로직을 구상 제품 클래스로부터 디커플링하는데 도움을 줄 뿐이다.
  • 구상 크리에이터(Concrete Creator)
    • 기초 팩토리 메서드를 오버라이드하여 다른 유형의 제품을 반환하게 하도록 함
  • 팩토리 메서드는 항상 새로운 인스턴스들을 생성해야 할 필요가 없다 팩토리 메서드는 기존 객체들을 캐시, 객체 풀 또는 다른 소스로부터 반환할 수 있다.

팩토리 메서드의 적용

  • 함께 작동해야 하는 객체들의 정확한 유형들과 의존관계들을 미리 모르는 경우에 사용
    • 팩토리 메서드는 제품 생성 코드를 제품을 실제로 사용하는 코드와 분리하기 때문에 제품 생성자 코드를 나머지 코드와는 독립적으로 확장하기 쉬워짐
  • 내가 만든 라이브러리/프레임워크의 사용자들에게 내부 컴포넌트들을 확장하는 방법을 제공하고 싶을 때 사용
    • 프레임워크 전체에서 컴포넌트들을 생성하는 코드를 단일 팩토리 메서드로 줄인 후 누구나 이팩토리 메서드를 오버라이드할 수 있도록 수행
  • 기존 객체들을 매번 재구축하는 대신 이들을 재사용하여 시스템 리소스를 절약하고 싶을 때 사용

다른 패턴과의 관계

  • 많은 디자인은 복잡성이 낮고 자식 클래스들을 통해 더 많은 커스터마이징이 가능한 팩토리 메서드로 시작해 더 유연하면서도 더 복잡한 추상 팩토리, 프로토타입 또는 빌더 패턴으로 발전해 나간다
  • 추상 팩토리 클래스들은 팩토리 메서드들의 집합을 기반으로 하는 경우가 많다. 또한 프로토타입을 사용해 추상 팩토리의 구상 클르스들의 생성 메서드들을 구현할 수도 있다
  • 프로토타입은 상속을 기반으로 하지 않으므로 상속과 관련된 단점들이 없지만 복제된 객체의 복잡한 초기화를 필요로 한다. 팩토리 메서드는 상속을 기반으로 하지만 초기화 단계가 필요하지 않다
  • 팩토리 메서드는 템플릿 메서드의 특수화라고 생각할 수 있다. 동시에 대규모 템플릿 메서드의 한 단계의 역할을 팩토리 메서드가 할 수 있다.
  • 생성하는 제품의 종류가 적을 경우 단순한 조건문으로 빠르게 구현한 심플 팩토리 메서드를 사용할 수 있다.

팩토리 메서드를 사용해 다양한 보스를 소환해보기

  • Boss
    • 제품 추상 클래스
public enum BossType
{
	NormalBoss,
	EventBoss
}


abstract class Boss : MonoBehaviour
{
	protected BossType type;
	protected int hp;
	protected int exp;
    public abstract void Attack();
}
  • EventBoss
    • 이벤트 기간에만 등장하는 보스몹
    • Attack() 오버라이딩
class EventBoss : Boss
{
	void Start()
	{
		type = BossType.EventBoss;
		hp = 200;
		exp = 20;

        name = "Event Boss";
        Debug.Log (this.name + " : 출현!!");
	}

    public override void Attack()
    {
        Debug.Log(this.name + " : 공격!!");
    }
}
  • NormalBoss
    • 평소 보스 몹
    • Attack() 오버라이딩
class NormalBoss : Boss
{
	void Start()
	{
		type = BossType.NormalBoss;
		hp = 200;
		exp = 15;

        name = "Normal Boss";
        Debug.Log (this.name + " : 출현!!");
	}

    public override void Attack()
    {
        Debug.Log(this.name + " : 공격!!");
    }
}
  • BossFactory
    • 크리에이터 추상 클래스
    • Boss (EventBoss, NormalBoss) 들을 생성한다
    • 어떤 보스를 생성해야할지는 모른다. 얘 입장에선 몰라도 됨. 그저 Boss (EventBoss, NormalBoss)들을 생성하고 리턴만 해주면 됨.
abstract class BossFactory : MonoBehaviour
{
	// Factory Method
	public abstract void CreateBoss(Transform tran); 
}
  • BossGenerator
    • 콘크리트 크리에이터 클래스
    • 어떤 종류의 Boss를 생성할지는 얘가 정한다.
    • 종류 추가 수정시 얘만 수정해주면 됨.
    • 슬롯에 들어가는 Boss 종류 오브젝트에 따라 다르게 리턴된다.
    • CreateBoss(Transform tran) 오버라이딩 -> 팩토리 메서드 패턴
class BossGenerator : BossFactory
{
    // 설날 코스튬 보스몹 지정
    public BossType type = BossType.EventBoss;
    public GameObject _normalBoss;
    public GameObject _eventBoss;

    public override void CreateBoss(Transform tran)
	{
        if (type == BossType.NormalBoss)
        {
            GameObject boss = Instantiate(_normalBoss) as GameObject;
            boss.transform.position = tran.position;
            boss.transform.localRotation = tran.localRotation;
        }
        else if (type == BossType.EventBoss)
        {
            GameObject boss = Instantiate(_eventBoss) as GameObject;
            boss.transform.position = tran.position;
            boss.transform.localRotation = tran.localRotation;
        }
    }
}
  • UseFactoryMethod
    • 팩토리를 실제로 사용하는 클라이언트
public class UseFactoryMethod : MonoBehaviour {

    BossGenerator factory = null;
    public Text desc;

	void Start () {
        factory = GetComponent<BossGenerator>();

        if (factory.type == BossType.NormalBoss)
        {
            desc.text = "Normal Boss";
        }
        else if (factory.type == BossType.EventBoss)
        {
            desc.text = "Event Boss";
        }

        // 로직에 따라 특정 위치 지정
        Transform tran = this.gameObject.transform;

        // 무엇이 만들어질지 여기서는 모른다.
        // 이벤트 기간에 맞춰 팩토리 클래스에서 타입이 변경되었다면
        // 해당 보스가 등장하게 된다.
        factory.CreateBoss(tran);
    }
}
profile
학습한 내용을 빠르게 다시 찾기 위한 저장소

0개의 댓글