추상 팩토리 패턴 : 동일한 주제의 다른 팩토리를 묶어 준다.
팩토리 메소드 패턴 : 생성할 객체의 클래스를 국한하지 않고 객체를 생성한다.
- 위키백과 -
이번에 알아볼건 팩토리 패턴이다.
이 패턴의 핵심 내용은 어떠한 객체를 생성, 분류하는 데 있어서 의존성을 낮추고 캡슐화하는 것이다.
이번에도 정의만 봐서는 어떤 건지 감이 오지 않기에 하나씩 풀어보며 알아가 보자.
(왜 개념 정의는 다 어려운 걸까)
추상 팩토리 패턴 : 객체의 집합을 구성할 때 사용한다.
이는 앞선 전략 패턴 (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);
이제 패턴을 정리해보며 마치도록 하겠다.
- 목적 : 객체를 생성 또는 분류, 관리하는 데 있어서 의존성을 낮추고 캡슐화하여 유지보수를 편하게 한다.
- 방법
- 추상 팩토리 패턴 : 객체의 집합(클래스, 인터페이스)을 정의하고 하위 클래스에서 세부 구현을 한다.
- 팩토리 메소드 패턴 : 자신의 클래스를 하위 클래스에 넘겨 세부적인 구현을 완성하여 자신을 완성한다.
- 템플릿 메소드 패턴 : 자신의 클래스를 하위 클래스에 넘겨 세부적인 구현을 완성하여 자유롭게 사용한다.
- 주의점 : 팩토리 메소드 패턴과 템플릿 메소드 패턴은 너무 무분별하게 사용할 경우
과도하게 많은 클래스가 생겨나서 오히려 역효과가 날 수 있으므로 적절하게 사용하는 것이 중요하다.
(위와 같이 간단하거나 그 양이 많지 않다면 한 클래스에 모아서 관리하는 편이 좋을지도 모른다.)
팩토리 패턴은 아마 알게 모르게 이미 쓰고 있었을 가능성이 높았을 거라 생각된다.
단지 그것의 패턴 명칭과 개념에 대해서 좀 더 알게 되었다고 생각하면 이해하는데 크게 어렵진 않을 것이다.
(간단한 예제로는 괜찮다가도 조금만 섞여있으면 많이 헷갈리는 패턴들이므로 개념 이해 정도면 충분하다.)
'디자인 패턴' 카테고리의 다른 글
5. 커맨드 패턴 (Command Pattern) (0) | 2020.12.23 |
---|---|
4. 데코레이터 패턴 (Decorator pattern) (0) | 2020.12.21 |
3. 싱글턴 패턴 (Singleton pattern) (0) | 2020.12.19 |
1. 전략 패턴 (Strategy Pattern) (0) | 2020.12.16 |
0. 디자인 패턴, 왜 알아야 할까? (2) | 2020.12.13 |