게임 개발/디자인 패턴

[디자인패턴] 5. 유니티에서 추상팩토리

Heesuk Lee 2021. 7. 27. 16:35

지난시간에는 팩토리메소드 패턴을 유니티에서 표현해봤습니다. 다음은 추상팩토리를 정리해보고자 합니다.

 

추상 팩토리의 특징은 인터페이스를 이용하여 서로 관련있는, 의존하는 객체를 구상클래스를 지정하지않고 생성하는 방식입니다.

팩토리메소드 패턴과 두드러진 차이점은 바로 구상클래스의 유무입니다.

 

그외의 특징이 있다면 게임을 예로들어서 '무기', '헬멧', '옷' 등 몬스터의 장비를 세팅하는 등의 규격이 정해진 어떠한 객체를 꾸며줘서 객체의 정의를 결정하는 시스템에 어울립니다.

일종의 옷입히기랄까...

 

 

2021.07.21 - [디자인패턴 정리] - [디자인패턴]4. 유니티에서 팩토리 메소드 패턴

 

[디자인패턴]4. 유니티에서 팩토리 메소드 패턴

유니티에서 객체를 생성하는 일이 많습니다. 몬스터, 장애물, 유저캐릭터 등등... 오늘 정리할 패턴은 위와같이 객체를 생성하는 것에 있어서 확장성이 높고 의존성을 줄일 수 있는 패턴 '팩토리

welcomeheesuk.tistory.com

 

팩토리 메소드 패턴에서 만들었던 고블린, 스켈레톤 생성 시스템을 변화시켜보겠습니다.

 

가장 기반이 되는 추상클래스 EquipmentFactory 입니다.

 

// 추상클래스패턴의 구현할 슈퍼클래스입니다.
public abstract class EquipmentFactory : MonoBehaviour
{
	// 몬스터 객체를 꾸며줄 추상 메소드들 입니다.
    public abstract Weapon CreateWeapon();
    public abstract Helmet CreateHelmet();
    public abstract BodyCloth CreateBodyCloth();
}

 

다음은 추상클래스를 상속받는 서브 클래스입니다. 고블린 장비 팩토리이므로 고블린 몬스터를 꾸며주는 장비들을 가지고 있습니다.

 

public class GoblinEquipmentFactory : EquipmentFactory
{
	// 장비 프리팹을 멤버변수로 가집니다.
    [SerializeField]
    private Weapon goblinWeapon = null;
    [SerializeField]
    private Helmet goblinHelmet = null;
    [SerializeField]
    private BodyCloth goblinBodyCloth = null;
	
    // 추상 메소드를 상속받아 구현합니다.
    public override Weapon CreateWeapon()
    {
        Weapon weapon = Instantiate(this.goblinWeapon).GetComponent<Weapon>();
        return weapon;
    }
    public override Helmet CreateHelmet()
    {
        Helmet helmet = Instantiate(this.goblinHelmet).GetComponent<Helmet>();
        return helmet;
    }
    public override BodyCloth CreateBodyCloth()
    {
        BodyCloth bodyCloth = Instantiate(this.goblinBodyCloth).GetComponent<BodyCloth>();
        return bodyCloth;
    }
}

 

다음은 기존에 없던 장비 멤버변수를 몬스터클래스에 추가해줍니다.

 

public abstract class Monster : MonoBehaviour
{
    // 몬스터 클래스에 무기, 헬멧, 옷 멤버변수를 추가합니다.
    protected Weapon weapon = null;
    protected Helmet helmet = null;
    protected BodyCloth bodyCloth = null;
    // 추상팩토리를 매개변수로 받는 장비 세팅하는 메소드를 추가합니다.
    public abstract void SetEquipment(EquipmentFactory _equipmentFactory);
}

 

고블린을 꾸며주기위해 고블린 클래스에 몬스터 클래스에 있는 SetEquipment 메소드를 구현해줍니다.

 

public class Goblin : Monster
{
	// 장비 팩토리 클래스를 멤버변수로 가집니다. (재활용의 가능성이 없다면 안가져도 됩니다.)
    private EquipmentFactory goblinEquipmentFactory = null;
    
    // 장비를 세팅해주는 추상메소드를 구현해줍니다.
    public override void SetEquipment(EquipmentFactory _equipmentFactory)
    {
        this.goblinEquipmentFactory = _equipmentFactory;

        this.weapon = this.goblinEquipmentFactory.CreateWeapon();
        this.weapon.transform.SetParent(this.transform, false);

        this.helmet = this.goblinEquipmentFactory.CreateHelmet();
        this.helmet.transform.SetParent(this.transform, false);

        this.bodyCloth = this.goblinEquipmentFactory.CreateBodyCloth();
        this.bodyCloth.transform.SetParent(this.transform, false);
    }
}

 

다음은 실행부 입니다. GoblinMonsterFactory가 장비클래스를 멤버변수로 가져 생성된 고블린을 꾸며줄 수 있습니다.

 

public class GoblinMonsterFactory : MonsterFactory<MONSTER_GOBLIN>
{
    // 고블린과 관련된 객체를 멤버변수로 가진다.
    [SerializeField]
    private GameObject goblinPrefab = null;
    [SerializeField]
    private GameObject goblinBigPrefab = null;
    [SerializeField]
    private GameObject goblinKingPrefab = null;
    

    [SerializeField]
    private EquipmentFactory equipmentFactory = null;

    // MonsterFactory에서 상속받은 create 함수를 꾸며준다.
    protected override Monster Create(MONSTER_GOBLIN _type)
    {        
        Goblin goblin = null;
        switch (_type)
        {
            // 매개변수로 받은 Enum변수를 기준으로 고블린 객체 생성
            case MONSTER_GOBLIN.NORMAL :
                goblin = Instantiate(this.goblinPrefab).GetComponent<Goblin>();
                break;
            case MONSTER_GOBLIN.BIG :
                goblin = Instantiate(this.goblinBigPrefab).GetComponent<Goblin>();
                break;
            case MONSTER_GOBLIN.KING :
                goblin = Instantiate(this.goblinKingPrefab).GetComponent<Goblin>();
                break;
        }
        
        // 고블린이 생성된 이후에 장비를 세팅해줘서 생성된 고블린 객체의 정의를 결정해줄수있습니다.
        goblin.SetEquipment(this.equipmentFactory);
        return goblin;
    }
}

 

 

고블린 원본

 

꾸며주는 장비 오브젝트들 무기,헬멧,옷 순서

 

스켈레톤 원본 오브젝트

 

꾸며주는 장비 오브젝트들 무기,헬멧,옷 순서

 

 

게임을 실행하게 되면 이렇게 몬스터의 무기,헬멧, 옷을 꾸며줘 생성하는 모습이 나옵니다.

 

 

 

팩토리 메소드 패턴과 추상팩토리 패턴을 섞어서 사용한 예시를 들었습니다만

실제 게임을 구현하시면서 이런상황에서 뿐만아니라 단일 플레이어 캐릭터를 커스터마이징된 장비들로 세팅을 한다던지 등의

 

추상팩토리 패턴 하나만 사용해 다양한 파트에서 활용 가능할것이라고 생각이 들었습니다.

 

다시 리마인드 하는 차원에서 게임에서 팩토리메소드패턴과 추상팩토리패턴의 특징을 정리해보겠습니다.

 

팩토리 메소드 패턴

어떠한 객체를 생산하는 생산자와 어떠한 객체를 생산할지 결정하는 구상 생산자의 분리

다양한 완제품을 생성할때 좋다.

몬스터와 같이 타입이 계속 늘어날 객체를 생성하기에 좋다.

 

추상팩토리 패턴

생산자와 구상 생산자의 분리를 하지 않는다.

객체를 꾸며서 제품을 완성시킬때 좋다.

객체의 타입이 중요하지않고 객체를 꾸며주는 요소가 많을때 사용하면 좋다.

(대신 꾸며주는 요소가 변동이 심하면 계속 추가 구현이 들어갈 수 있는 단점이 있다.)

 

 

생각보다 깊이가 있는 패턴을 다뤄 아직까지 혼란스러운 부분은 있지만

앞으로 다양한 실사례 구현 경험을 통해 단단해질것이라 생각이 듭니다.

현기증 날 것 같아요...

 

반응형