팩토리 패턴

송칭·2024년 11월 11일
0

디자인패턴

목록 보기
7/8

팩토리 패턴은 객체의 생성에 관련된 디자인 패턴 중 하나다. 객체를 생성하는 로직을 캡슐화하여 유지보수성과 확장성을 높이기 위해서 사용한다.

팩토리 패턴에는 크게 심플 팩토리 패턴, 팩토리 메서드 패턴, 추상 팩토리 패턴의 3가지가 있다.
이 셋을 비교하고 예시를 만들어 보기위해 가장 단순한 심플 팩토리를 먼저 알아보자.

다음은 아주 간단한 구조다. 단지 몬스터를 생성하는 로직을 MonsterFactory 클래스로 분리해 둔 것이다.
MonsterType 열거형으로 몬스터 종류를 구분하고 new 키워드로 새로운 몬스터를 만들어 반환한다.

public enum MonsterType
{
	Slime,
	Wolf
}

public interface Monster
{
	public void Growl();
}

public class Slime : Monster
{
	public void Growl()
	{
        Console.WriteLine("뾱!뾱!");
	}
}

public class Wolf : Monster
{
	public void Growl()
	{
		Console.WriteLine("아우~");
	}
}

public class MonsterFactory
{
	public Monster CreateMonster(MonsterType type)
	{
		switch (type)
		{
			case MonsterType.Slime:
				return new Slime();
			case MonsterType.Wolf:
				return new Wolf();
			default:
				return null;
		}
	}
}

public class Program
{
	public static void Main(string[] args)
	{
		MonsterFactory factory = new MonsterFactory();
		Monster mob1 = factory.CreateMonster(MonsterType.Slime);
		Monster mob2 = factory.CreateMonster(MonsterType.Wolf);

		mob1.Growl();
		mob2.Growl();
	}
}

하지만 이런 구조는 디자인 패턴으로 따로 분리하기에는 다소 애매한 부분이 있다. 어찌되었든 새로운 몬스터를 추가할 때, MonsterFactory 클래스를 수정해주어야 하기 때문에 OCP를 위반하고 있다. 그러면 MonsterFactory를 상속하는 SlimeFactory, WolfFactory를 만들어주면 되지 않을까? 그렇다. 그것이 바로 팩토리 메서드 패턴이다. 팩토리 메서드 패턴에서는 객체 생성을 자식 클래스들에게 위임한다.

public abstract class MonsterFactory
{
	public abstract Monster CreateMonster();
}

public class SlimeFactory : MonsterFactory
{
	public override Monster CreateMonster()
	{
		return new Slime();
	}
}

public class WolfFactory : MonsterFactory
{
	public override Monster CreateMonster()
	{
		return new Wolf();
	}
}

public class Program
{
	public static void Main(string[] args)
	{
		MonsterFactory slimeFactory = new SlimeFactory();
		MonsterFactory wolfFactory = new WolfFactory();
		Monster mob1 = slimeFactory.CreateMonster();
		Monster mob2 = wolfFactory.CreateMonster();

		mob1.Growl();
		mob2.Growl();
	}
}

팩토리 메서드의 핵심은 열거형이나 스트링을 비교하지 않고 객체 생성을 위한 인터페이스를 정의하고, 객체마다 구체적인 생성 로직을 서브 클래스가 구현하게 하는 것이다. 이로써, Main은 구체적인 생성 로직에 의존하지 않고 서브 클래스만 알고 있으면 객체를 생성해 낼 수 있다.

그렇다면 추상 팩토리 패턴은 무엇일까? 추상 팩토리 패턴은 관련된 객체들을 그룹으로 생성하는 인터페이스를 제공해 준다. 그렇기때문에 어떤 종류의 몬스터를 생성할지만 고려하는 팩토리 메서드와는 다르게 타입뿐만 아니라 다른 관련된 객체를 함께 생성해야 할 때 유용하다.

예를 들자면 Forest와 Cave라는 맵이 있다. 여기에 각각의 레벨에 맞는 몬스터와 NPC가 함께 생성되어야하므로 이를 추상 팩토리로 묶는 것이 적절하다.

각각의 맵에 존재할 NPC들을 먼저 만들어보자.

public abstract class NPC
{
	public abstract void Speak();
    
}

public class ForestNPC : NPC
{
	public override void Speak()
	{
		Console.WriteLine("숲에서 길을 잃었어요.");
	}
}

public class CaveNPC : NPC
{
	public override void Speak()
	{
		Console.WriteLine("이곳은 위험합니다.");
	}
}

그리고 몬스터만 생성하는 것이 아닌 몬스터와 NPC를 포함한 맵 레벨을 만들어 줄 추상 팩토리 LevelFactory가 필요하다.

public abstract class LevelFactory
{
	public abstract Monster CreateMonster();
	public abstract NPC CreateNPC();
}

public class ForestLevelFactory : LevelFactory
{
	public override Monster CreateMonster()
	{
		return new Slime();
	}

	public override NPC CreateNPC()
	{
		return new ForestNPC();
	}
}

public class CaveLevelFactory : LevelFactory
{
	public override Monster CreateMonster()
	{
		return new Wolf();
	}

	public override NPC CreateNPC()
	{
		return new CaveNPC();
	}
}

public class Program
{
	public static void Main(string[] args)
	{
		LevelFactory forestFactory = new ForestLevelFactory();
		Monster forestMonster = forestFactory.CreateMonster();
		NPC forestNPC = forestFactory.CreateNPC();

		forestNPC.Speak();
		forestMonster.Growl();

		LevelFactory caveFactory = new CaveLevelFactory();
		Monster caveMonster = caveFactory.CreateMonster();
		NPC caveNPC = caveFactory.CreateNPC();

		caveNPC.Speak();
		caveMonster.Growl();
	}
}

연관된 객체들(몬스터와 NPC)을 함께 생성하는 구조가 필요할 때, 추상 팩토리 패턴을 사용하면 된다. CreateMonster()와 CreateNPC()를 하나로 묶는 CreateLevel() 메서드를 생성해도 좋다.

profile
게임 클라이언트

0개의 댓글