[Design Pattern] 팩토리(Factory) 패턴
팩토리(Factory) 패턴이란?
팩토리 패턴은 객체 생성을 위한 인터페이스를 정의하고, 어떤 클래스의 인스턴스를 생성할지는 서브클래스에서 결정하도록 하는 디자인 패턴입니다.
즉, 객체 생성 로직을 캡슐화하여 클라이언트 코드에서 구체 클래스에 대한 의존성을 제거합니다.
팩토리(Factory)의 종류
- 단순 팩토리 (Simple Factory): 객체 생성을 담당하는 하나의 클래스를 사용합니다. 팩토리 클래스 내부에 조건문을 사용하여 어떤 객체를 생성할지 결정합니다.
- 팩토리 메서드 (Factory Method): 객체 생성을 위한 인터페이스를 정의하고, 구체적인 객체 생성은 서브클래스에서 담당하도록 합니다.
- 추상 팩토리 (Abstract Factory): 관련 있는 객체들을 생성하기 위한 인터페이스를 제공하며, 구체적인 팩토리를 통해 객체를 생성합니다.
팩토리(Factory) 패턴의 장단점
장점
- 객체 생성 로직 캡슐화: 객체 생성 로직을 팩토리 클래스에 캡슐화하여 클라이언트 코드에서 구체 클래스에 대한 의존성을 제거합니다.
- 유연성 향상: 새로운 객체 타입을 추가하더라도 기존 코드를 수정할 필요가 없습니다. 새로운 팩토리 클래스를 추가하면 됩니다.
- 코드 재사용성 향상: 객체 생성 로직을 재사용할 수 있습니다.
- OCP (Open/Closed Principle) 준수: 확장에 대해서는 열려 있고, 변경에 대해서는 닫혀 있는 객체지향 디자인 원칙을 준수합니다.
단점
- 클래스 증가: 팩토리 클래스를 추가해야 하므로, 클래스 수가 증가할 수 있습니다. (특히 팩토리 메서드, 추상 팩토리)
- 복잡성 증가: 객체 생성 로직이 복잡한 경우, 팩토리 패턴을 적용하면 코드의 복잡성이 증가할 수 있습니다.
구현
[단순 팩토리]
#include <iostream>
#include <string>
class Product { // 제품 인터페이스
public:
virtual ~Product() {}
virtual void use() = 0;
};
class ConcreteProductA : public Product { // 구체적인 제품 A
public:
void use() override {
std::cout << "Using ConcreteProductA" << std::endl;
}
};
class ConcreteProductB : public Product { // 구체적인 제품 B
public:
void use() override {
std::cout << "Using ConcreteProductB" << std::endl;
}
};
class SimpleFactory { // 단순 팩토리
public:
static Product* createProduct(char type) {
if (type == 'A') {
return new ConcreteProductA();
} else if (type == 'B') {
return new ConcreteProductB();
} else {
return nullptr; // 잘못된 타입
}
}
};
int main() {
Product* productA = SimpleFactory::createProduct('A');
if (productA != nullptr) {
productA->use(); // Using ConcreteProductA
delete productA;
}
Product* productB = SimpleFactory::createProduct('B');
if (productB != nullptr) {
productB->use(); // Using ConcreteProductB
delete productB;
}
Product* productC = SimpleFactory::createProduct('C'); // 잘못된 타입
if (productC == nullptr){
std::cout << "Invalid product type" << std::endl;
}
return 0;
}
[팩토리 메서드 (Factory Method)] 팩토리 메서드 패턴은 객체 생성을 위한 인터페이스를 정의하고, 구체적인 객체 생성은 서브클래스에서 담당하도록 합니다.
#include <iostream>
#include <string>
class Product { // 제품 인터페이스
public:
virtual ~Product() {}
virtual void use() = 0;
};
class ConcreteProductA : public Product { // 구체적인 제품 A
public:
void use() override {
std::cout << "Using ConcreteProductA" << std::endl;
}
};
class ConcreteProductB : public Product { // 구체적인 제품 B
public:
void use() override {
std::cout << "Using ConcreteProductB" << std::endl;
}
};
class Creator { // 생성자 인터페이스
public:
virtual ~Creator() {}
virtual Product* createProduct() = 0;
void someOperation() {
Product* product = this->createProduct();
product->use();
delete product;
}
};
class ConcreteCreatorA : public Creator { // 구체적인 생성자 A
public:
Product* createProduct() override {
return new ConcreteProductA();
}
};
class ConcreteCreatorB : public Creator { // 구체적인 생성자 B
public:
Product* createProduct() override {
return new ConcreteProductB();
}
};
int main() {
Creator* creatorA = new ConcreteCreatorA();
creatorA->someOperation(); // Using ConcreteProductA
delete creatorA;
Creator* creatorB = new ConcreteCreatorB();
creatorB->someOperation(); // Using ConcreteProductB
delete creatorB;
return 0;
}