팩토리(Factory) 패턴
팩토리 패턴은 객체 생성을 담당하는 클래스를 분리하여 코드의 유지소수성과 확장성을 높이는 디자인 패턴이다.
즉, 객체 생성 로직을 캡슐화하고 객체 생성을 클라이언트 코드에서 분리할 때 사용한다.
주요 개념
- 팩토리(Factory)
- 객체 생성을 담당하며 클라이언트가 직접 객체를 생성하지 않도록 함
- 상속을 활용하여 다양한 하위 클래스 생성 가능
graph TD
A[Client] -->|Request| B[Factory]
B -->|Create and return| C[Product A]
B -->|Create and return| D[Product B]
subgraph "Structure of Factory"
B
C
D
end
장점
- 객체 생성 로직을 클라이언트에서 분리 가능 → 유지보수성 향상
- 새로운 제품을 추가할 때 팩토리 클래스만 수정하면 됨
- 의존성을 줄이고, 코드의 유연성을 높임
주의점
- 제품군(Product)과 팩토리의 관계를 명확한 정의 필요
- 팩토리는 반환할 객체의 인터페이스(또는 추상 클래스)를 기반으로 동작해야 함
- 구체적인 클래스에 의존하지 않도록 스마트 포인터를 사용을 추천
- 팩토리의 확장성 고려
- 새로운 제품을 추가할 때 Factory의 if-else 문이 길어질 수 있음
- 이러한 경우에는 등록 기반 팩토리(Factory Map) 또는 추상 팩토리(Factory Method 패턴)를 고려
- 메모리 누수, 오버헤드 문제 주의
- 팩토리 패턴은 객체를 동적으로 생성하는 경우가 많아 성능 및 메모리 관리 필요
std::unique_ptr 또는 std::shared_ptr을 사용하여 메모리 누수를 방지필요- 객체 생성 비용이 크다면
싱글톤(Singleton)이나 객체 풀(Object Pool) 패턴과 조합을 고려
의존성 주입(DI)와의 조합 고려- 팩토리 패턴만 사용할 경우 객체 생성이 팩토리에 묶일 수 있음
- 의존성 주입(DI) 프레임워크와 함께 사용하면 더 유연한 설계가 가능
예시
C++을 이용하여 예시 코드를 작성하였다. 아래 링크에서 전체를 확인할 수 있다.
https://github.com/grade-e/factory-cpp-container
Class diagram
classDiagram
class Sensor {
+virtual ~Sensor()
+virtual void read() const = 0
+int getId() const
}
class TemperatureSensor {
+TemperatureSensor(int id)
+void read() const override
}
class PressureSensor {
+PressureSensor(int id)
+void read() const override
}
class SensorModule {
+virtual ~SensorModule()
+void readAll() const
#vector<unique_ptr<Sensor>> sensors_
#static int counter_
}
class TemperatureSensorModule {
+TemperatureSensorModule(int sensorCount)
}
class PressureSensorModule {
+PressureSensorModule(int sensorCount)
}
class SensorFactory {
+static unique_ptr<SensorModule> createTemperatureModule(int sensorCount)
+static unique_ptr<SensorModule> createPressureModule(int sensorCount)
}
Sensor <|-- TemperatureSensor
Sensor <|-- PressureSensor
SensorModule <|-- TemperatureSensorModule
SensorModule <|-- PressureSensorModule
SensorModule "1" *-- "many" Sensor : contains
SensorFactory --> TemperatureSensorModule
SensorFactory --> PressureSensorModule
코드
Sensor
- 추상 클래스이므로, 직접 객체로 생성되지 않음
- 센서 객체는 read() 메서드를 가지며, ID를 고유한 정수값으로 부여.
1
2
3
4
5
6
7
8
9
10
11
12
| class Sensor {
public:
virtual ~Sensor() = default;
virtual void read() const = 0;
int getId() const { return id_; }
protected:
explicit Sensor(int id) : id_(id) {}
private:
int id_;
};
|
Range sensor, Temperature sensor
Sensor를 상속받아 거리센서, 온도센서 처리- 생성될 때 id를 부여받음
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| class RangeSensor : public Sensor {
public:
explicit RangeSensor(int id) : Sensor(id) {}
void read() const override {
std::cout << "Reading data from range sensor " << getId() << std::endl;
}
};
class TemperatureSensor : public Sensor {
public:
TemperatureSensor(int id) : Sensor(id) {}
void read() const override {
std::cout << "Reading data from temperature sensor " << getId()
<< std::endl;
}
};
|
SensorModule
- 추상 클래스이므로, 직접 객체로 생성되지 않음
- 각 센서를 관리 및 데이터 처리하는 역할을 수행
- 센서를 여러 개 포함하는 집합적 개념
- 센서 객체들의 컨테이너
std::vector<unique_ptr<Sensor>>를 포함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| class SensorModule {
public:
virtual ~SensorModule() = default;
virtual void processData() const = 0; // 센서 모듈별 데이터 처리 방식
void readAll() const {
for (const auto& sensor : sensors_) {
sensor->read();
}
}
protected:
std::vector<std::unique_ptr<Sensor>> sensors_;
static int counter_;
};
|
Range sensor module, Temperature sensor module
SensorModule을 상속받아, 각각 온도 센서와 압력 센서를 관리하는 모듈- 센서의 개수를 인자로 받아, 생성자에서 자동으로 센서를 추가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
class RangeSensorModule : public SensorModule {
public:
explicit RangeSensorModule(int count) {
counter_ = 0;
for (int i = 0; i < count; ++i) {
sensors_.push_back(std::make_unique<RangeSensor>(++counter_));
}
}
void processData() const override {
std::cout << "[Range Module] Processing range data..." << std::endl;
}
private:
int counter_;
};
class TemperatureSensorModule : public SensorModule {
public:
explicit TemperatureSensorModule(int count) {
counter_ = 0;
for (int i = 0; i < count; ++i) {
sensors_.push_back(std::make_unique<TemperatureSensor>(++counter_));
}
}
void processData() const override {
std::cout << "[Temperature Module] Processing temperature data..."
<< std::endl;
}
private:
int counter_;
};
|
Sensor Factory
SensorModule을 직접 생성하는 것이 아니라, Factory를 통해 객체 생성을 캡슐화
1
2
3
4
5
6
7
8
9
10
| class SensorFactory {
public:
static std::unique_ptr<SensorModule> createTemperatureModule(int count) {
return std::make_unique<TemperatureSensorModule>(count);
}
static std::unique_ptr<SensorModule> createRangeModule(int count) {
return std::make_unique<RangeSensorModule>(count);
}
};
|
main()
Range sensor, Temparature sensor의 생성 갯수를 Factory에서 지정Factory에서 각 SensorModule 생성 이후, 제어는 SensorModule에서 진행
1
2
3
4
5
6
7
8
9
10
11
12
| int main() {
auto tempModule = SensorFactory::createTemperatureModule(2);
auto rangeModule = SensorFactory::createRangeModule(3);
tempModule->readAll();
rangeModule->readAll();
tempModule->processData();
rangeModule->processData();
return 0;
}
|
실행 결과
1
2
3
4
5
6
7
| Reading data from temperature sensor 1
Reading data from temperature sensor 2
Reading data from range sensor 1
Reading data from range sensor 2
Reading data from range sensor 3
[Temperature Module] Processing temperature data...
[Range Module] Processing range data...
|