본문 바로가기

디자인 패턴

2. 팩토리 패턴 (Factory Pattern)

추상 팩토리 패턴 : 동일한 주제의 다른 팩토리를 묶어 준다.
팩토리 메소드 패턴 : 생성할 객체의 클래스를 국한하지 않고 객체를 생성한다.
- 위키백과 -

이번에 알아볼건 팩토리 패턴이다.

이 패턴의 핵심 내용은 어떠한 객체를 생성, 분류하는 데 있어서 의존성을 낮추고 캡슐화하는 것이다.

이번에도 정의만 봐서는 어떤 건지 감이 오지 않기에 하나씩 풀어보며 알아가 보자.

(왜 개념 정의는 다 어려운 걸까)

 

 

추상 팩토리 패턴 : 객체의 집합을 구성할 때 사용한다.

이는 앞선 전략 패턴 (Strategy Pattern) 에서

ISpecialEffect 와 그 아래 구현된 SEFire, SEIce 와 같은 형태라고 볼 수 있다.

 

즉, 아이템, 스킬, 재료와 같은 단일 객체들의 집합에 적용하여 사용할 수 있다.

 

public interface IMaterial
{
    string Name { get; }
}

public class Wood : IMaterial
{
    public string Name { get => "나무"; }
}

public class Iron : IMaterial
{
    public string Name { get => "철"; }
}

 

 

팩토리 메소드 패턴 : 하위 클래스에 구체적인 구현을 넘겨서 객체를 생성한다.

하위 클래스에 구체적인 구현을 넘긴다는 말은 쉽게 이해가 될 것이다.

이 패턴의 핵심은 이를 통해 객체를 생성한다는 점인데 아래 코드와 함께 살펴보자.

 

public enum ForgeType
{
    MAGIC,
    SWORD
}

public abstract class Forge
{
    public abstract List<string> GetProduct();

    public static Forge CreateForge(ForgeType type)
    {
        switch (type)
        {
            case ForgeType.MAGIC:
                return new MagicForge();
            case ForgeType.SWORD:
                return new SwordForge();
        }
        return null;
    }
}

public class MagicForge : Forge
{
    public override List<string> GetProduct()
    {
        var list = new List<string>();
        list.Add("초급 지팡이");
        list.Add("중급 지팡이");
        return list;
    }
}

public class SwordForge : Forge
{
    public override List<string> GetProduct()
    {
        var list = new List<string>();
        list.Add("나무 검");
        list.Add("철 검");
        return list;
    }
}

 

Forge 에 자신을 생성하는 함수인 CreateForge 함수가 있고

MagicForge 와 SwordForge 를 타입에 따라서 생성하여 반환해준다.

 

이때 MagicForge 와 SwordForge 는 추상 메소드인 GetProduct 를 오버라이드 하여 

자신에게 맞는 상품을 반환해준다.

 

얼핏 보면 세부적인 구현을 다른 클래스에 넘겨 캡슐화한다는 점에서

앞선 전략 패턴 (Strategy Pattern) 과 유사하다고 볼 수 있지만

값을 바꿔가면서 쓰는것이 아니며 팩토리 메소드 패턴은 자신의 클래스를 하위에 넘겨서 세부적인 구현 하여

자신을 완성한다는 점에서 명확한 차이가 있다.


템플릿 메소드 패턴 : 하위 클래스에 구체적인 구현을 넘겨서 객체를 사용한다.

팩토리 패턴과는 다른 내용이지만 팩토리 패턴과 함께 알아두면 좋을 것 같아서 같이 소개해보겠다.

 

public enum ForgeType
{
    MAGIC,
    SWORD
}

public abstract class Forge
{
    public abstract List<string> GetProduct();
}

public class MagicForge : Forge
{
    public override List<string> GetProduct()
    {
        var list = new List<string>();
        list.Add("초급 지팡이");
        list.Add("중급 지팡이");
        return list;
    }
}

public class SwordForge : Forge
{
    public override List<string> GetProduct()
    {
        var list = new List<string>();
        list.Add("나무 검");
        list.Add("철 검");
        return list;
    }
}

 

위 팩토리 메소드 패턴을 템플릿 메소드 패턴으로 변경한 것이다.

Forge 에 자신을 생성하는 함수인 CreateForge 가 없어진 걸 제외하면 다른 게 없는 코드이다.

 

팩토리 메소드 패턴과 유사하지만 자신의 클래스를 하위에 넘겨서 세부적인 구현 하여

자유롭게 사용한다는 점에서 다르다.

이 두 코드를 사용한다면 아래와 같을 것이다.

 

// 팩토리 메소드 패턴
var magicForge = Forge.CreateForge(ForgeType.MAGIC);
foreach (var product in magicForge.GetProduct())
	Console.WriteLine(product);

// 템플릿 메소드 패턴
var swordForge = SwordForge();
foreach (var product in swordForge.GetProduct())
	Console.WriteLine(product);

이제 패턴을 정리해보며 마치도록 하겠다.

 

  • 목적 : 객체생성 또는 분류, 관리하는 데 있어서 의존성을 낮추고 캡슐화하여 유지보수를 편하게 한다.
  • 방법
    • 추상 팩토리 패턴 : 객체의 집합(클래스, 인터페이스)을 정의하고 하위 클래스에서 세부 구현을 한다.
    • 팩토리 메소드 패턴 : 자신의 클래스하위 클래스에 넘겨 세부적인 구현을 완성하여 자신을 완성한다.
    • 템플릿 메소드 패턴 : 자신의 클래스하위 클래스에 넘겨 세부적인 구현을 완성하여 자유롭게 사용한다.
  • 주의점 : 팩토리 메소드 패턴템플릿 메소드 패턴은 너무 무분별하게 사용할 경우
                 과도하게 많은 클래스가 생겨나서 오히려 역효과가 날 수 있으므로 적절하게 사용하는 것이 중요하다.
                (위와 같이 간단하거나 그 양이 많지 않다면 한 클래스에 모아서 관리하는 편이 좋을지도 모른다.)

 

팩토리 패턴은 아마 알게 모르게 이미 쓰고 있었을 가능성이 높았을 거라 생각된다.

단지 그것의 패턴 명칭과 개념에 대해서 좀 더 알게 되었다고 생각하면 이해하는데 크게 어렵진 않을 것이다.

(간단한 예제로는 괜찮다가도 조금만 섞여있으면 많이 헷갈리는 패턴들이므로 개념 이해 정도면 충분하다.)