관련 영상
팩토리 메서드
위키피디아
설명 및 스도코드
- Factory method는 부모(상위) 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴이며 자식(하위) 클래스가 어떤 객체를 생성할지를 결정하도록 하는 패턴이기도 하다.
- 부모(상위) 클래스 코드에 구체 클래스 이름을 감추기 위한 방법으로도 사용한다.
- 팩토리 메서드는 템플릿 메서드의 생성 패턴 버전으로 볼 수 있다.
팩토리 메서드의 구조
![](https://velog.velcdn.com/images/_hoya_/post/d8a005d8-989d-48ff-9687-e4dae293c73f/image.png)
- 제품 인터페이스(Product Interface)
- 생성자와 자식 클래스들이 생성할 수 있는 모든 객체에 공통
- 구상 제품(Concrete Product)
- 크리에이터(Creator)
- 새로운 제품 객체들을 반환하는 팩토리 메서드 선언. 팩토리 메서드의 반환 유형이 제품 인터페이스와 일치해야 함
- 팩토리 메서드를 추상 클래스로 선언하여 모든 자식 클래스들이 각각 이 메서드의 자체 버전들을 구현하도록 강제하거나, 대안적으로 기초 팩토리 메서드가 디폴트 제품 유형을 반환하도록 만들 수도 있다.
- 크리에이터의 주책임은 제품 생산이 아니다. 일반적으로 크리에이터 클래스에는 이미 제품과 관련된 핵심 비즈니스 로직이 있고 팩토리 메서드는 이 로직을 구상 제품 클래스로부터 디커플링하는데 도움을 줄 뿐이다.
- 구상 크리에이터(Concrete Creator)
- 기초 팩토리 메서드를 오버라이드하여 다른 유형의 제품을 반환하게 하도록 함
- 팩토리 메서드는 항상 새로운 인스턴스들을 생성해야 할 필요가 없다 팩토리 메서드는 기존 객체들을 캐시, 객체 풀 또는 다른 소스로부터 반환할 수 있다.
팩토리 메서드의 적용
- 함께 작동해야 하는 객체들의 정확한 유형들과 의존관계들을 미리 모르는 경우에 사용
- 팩토리 메서드는 제품 생성 코드를 제품을 실제로 사용하는 코드와 분리하기 때문에 제품 생성자 코드를 나머지 코드와는 독립적으로 확장하기 쉬워짐
- 내가 만든 라이브러리/프레임워크의 사용자들에게 내부 컴포넌트들을 확장하는 방법을 제공하고 싶을 때 사용
- 프레임워크 전체에서 컴포넌트들을 생성하는 코드를 단일 팩토리 메서드로 줄인 후 누구나 이팩토리 메서드를 오버라이드할 수 있도록 수행
- 기존 객체들을 매번 재구축하는 대신 이들을 재사용하여 시스템 리소스를 절약하고 싶을 때 사용
다른 패턴과의 관계
- 많은 디자인은 복잡성이 낮고 자식 클래스들을 통해 더 많은 커스터마이징이 가능한 팩토리 메서드로 시작해 더 유연하면서도 더 복잡한 추상 팩토리, 프로토타입 또는 빌더 패턴으로 발전해 나간다
- 추상 팩토리 클래스들은 팩토리 메서드들의 집합을 기반으로 하는 경우가 많다. 또한 프로토타입을 사용해 추상 팩토리의 구상 클르스들의 생성 메서드들을 구현할 수도 있다
- 프로토타입은 상속을 기반으로 하지 않으므로 상속과 관련된 단점들이 없지만 복제된 객체의 복잡한 초기화를 필요로 한다. 팩토리 메서드는 상속을 기반으로 하지만 초기화 단계가 필요하지 않다
- 팩토리 메서드는 템플릿 메서드의 특수화라고 생각할 수 있다. 동시에 대규모 템플릿 메서드의 한 단계의 역할을 팩토리 메서드가 할 수 있다.
- 생성하는 제품의 종류가 적을 경우 단순한 조건문으로 빠르게 구현한 심플 팩토리 메서드를 사용할 수 있다.
팩토리 메서드를 사용해 다양한 보스를 소환해보기
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 + " : 공격!!");
}
}
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;
}
}
}
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);
}
}