팩토리 메소드(Factory Method) 패턴 이해하기
소프트웨어 설계에서 객체 생성을 보다 유연하게 하기 위해 고안된 팩토리 메소드(Factory Method) 패턴은 객체 생성 과정을 상속을 통해 캡슐화하는 생성 패턴 중 하나입니다. 팩토리 메소드 패턴을 적용하면 클라이언트 코드와 객체 생성 코드를 분리할 수 있어, 새로운 객체 유형이 추가되더라도 기존 코드에 최소한의 수정만으로 확장할 수 있습니다.
이번 포스트에서는 팩토리 메소드 패턴이 무엇이며, 어떤 상황에서 유용한지, 장단점과 구현 방법을 알아보겠습니다.
팩토리 메소드 패턴이란?
팩토리 메소드 패턴은 상위 클래스에서 객체 생성을 정의하고, 하위 클래스에서 구체적인 객체의 인스턴스를 생성하도록 위임하는 패턴입니다. 즉, 상위 클래스에서 팩토리 메소드를 통해 생성할 객체의 타입을 정의하지만, 실제 객체 생성은 하위 클래스가 결정하는 방식입니다.
이 패턴의 핵심은 객체 생성의 책임을 상위 클래스가 아닌 하위 클래스가 가지게 함으로써 클라이언트 코드가 객체의 구체적인 생성 방식을 몰라도 되는 것입니다.
팩토리 메소드 패턴의 구조
팩토리 메소드 패턴의 기본 구조는 다음과 같습니다.
- Product (제품 인터페이스): 생성할 객체가 가져야 하는 인터페이스를 정의합니다.
- ConcreteProduct (구체적인 제품): 실제로 생성되는 객체의 클래스입니다. Product 인터페이스를 구현하여 구체적인 기능을 제공합니다.
- Creator (창조자 인터페이스): 팩토리 메소드를 정의하는 추상 클래스 또는 인터페이스입니다. 이 클래스는 Product 객체를 반환하는 팩토리 메소드를 포함합니다.
- ConcreteCreator (구체적인 창조자): Creator를 상속받아 팩토리 메소드를 구현하는 클래스입니다. 여기서 구체적인 Product 인스턴스를 생성합니다.
예시 코드
// Product 인터페이스
public interface IProduct
{
string Operation();
}
// ConcreteProduct 클래스
public class ConcreteProductA : IProduct
{
public string Operation()
{
return "Product A created";
}
}
public class ConcreteProductB : IProduct
{
public string Operation()
{
return "Product B created";
}
}
// Creator 클래스
public abstract class Creator
{
// 팩토리 메소드
public abstract IProduct FactoryMethod();
public string SomeOperation()
{
var product = FactoryMethod();
return "Creator: " + product.Operation();
}
}
// ConcreteCreator 클래스
public class ConcreteCreatorA : Creator
{
public override IProduct FactoryMethod()
{
return new ConcreteProductA();
}
}
public class ConcreteCreatorB : Creator
{
public override IProduct FactoryMethod()
{
return new ConcreteProductB();
}
}
// 클라이언트 코드
public class Client
{
public void Main()
{
Creator creatorA = new ConcreteCreatorA();
Console.WriteLine(creatorA.SomeOperation());
Creator creatorB = new ConcreteCreatorB();
Console.WriteLine(creatorB.SomeOperation());
}
}
위 코드에서 ConcreteCreatorA는 ConcreteProductA를, ConcreteCreatorB는 ConcreteProductB를 생성하는 방식으로 각각 팩토리 메소드를 통해 특정 제품을 반환합니다. 클라이언트는 각 구체적인 Creator 객체에 의존하여 Product 객체를 생성하며, 제품이 추가되더라도 기존 코드를 수정하지 않고 새로운 ConcreteCreator만 추가하면 됩니다.
팩토리 메소드 패턴의 장단점
장점
- 코드의 유연성 증가: 객체 생성 로직과 클라이언트 코드가 분리되므로 객체 유형이 바뀌어도 클라이언트 코드는 수정이 필요 없습니다.
- 확장성: 새로운 제품이 추가되더라도 기존 코드에 최소한의 수정만으로 확장할 수 있어 유지보수가 쉽습니다.
- 상속을 통한 객체 생성 관리: 하위 클래스가 어떤 객체를 생성할지 결정할 수 있어 코드의 일관성이 높아집니다.
단점
- 클래스 증가: 팩토리 메소드 패턴을 적용하면 구체적인 생성자를 위한 새로운 클래스를 생성해야 하므로 클래스의 수가 많아져 복잡도가 높아질 수 있습니다.
- 상속에 의존: 팩토리 메소드 패턴은 상속을 통해 동작하므로, 코드의 유연성을 높이기 위해 다른 디자인 패턴과 결합하여 사용할 필요가 있을 수 있습니다.
언제 팩토리 메소드 패턴을 사용해야 할까?
팩토리 메소드 패턴은 다양한 유형의 객체를 생성해야 하는데, 클라이언트 코드와 객체 생성 코드를 분리하고자 할 때 유용합니다. 다음과 같은 경우에 적용할 수 있습니다.
- 유형에 따라 생성할 객체가 달라져야 할 때: 예를 들어, 문서 편집기 프로그램에서 WordDocument와 PdfDocument라는 두 가지 타입의 문서를 생성할 수 있다고 가정해봅시다. 이때 각 문서를 생성하는 로직을 팩토리 메소드로 분리하면 코드의 가독성과 유연성을 높일 수 있습니다.
- 객체 생성 로직이 자주 변경될 때: 객체 생성 로직이 복잡하거나 변경될 가능성이 높은 경우, 팩토리 메소드 패턴을 통해 생성 로직을 독립적으로 관리할 수 있습니다.
- 클라이언트 코드가 객체의 구체적인 클래스에 의존하지 않도록 할 때: 구체적인 클래스 대신 인터페이스나 추상 클래스를 통해 객체를 생성하여, 클라이언트가 생성된 객체의 구체적인 유형을 알 필요가 없도록 할 수 있습니다.
팩토리 메소드 패턴은 객체 생성의 책임을 상위 클래스에서 하위 클래스로 위임함으로써 코드의 유연성을 높이고, 확장 가능하게 만드는 강력한 디자인 패턴입니다. 이 패턴을 사용하면 생성될 객체의 구체적인 유형이 변경되더라도 코드 수정 없이 확장이 가능하므로 유지보수가 편리해집니다.
소프트웨어 설계에서 객체 생성에 대한 유연성과 확장성을 고민해야 할 때, 팩토리 메소드 패턴을 고려해 보시기 바랍니다.
'Thinking > Concept' 카테고리의 다른 글
빌더 패턴(Builder Pattern) 이해하기 (1) | 2024.11.14 |
---|---|
추상 팩토리 패턴(Abstract Factory Pattern) 이해하기 (0) | 2024.11.14 |
개발자를 위한 필수 디자인 패턴 23가지 GoF 패턴 총정리 (0) | 2024.11.13 |
의사 코드(Pseudo Code)(슈도 코드, 가짜 코드)란? (0) | 2023.09.03 |
알고리즘(Algorithm)이란 (0) | 2023.08.30 |