reference: "모던 C++ 디자인패턴" / 드미트리 네스터룩
직교 좌표계의 좌표 정보를 저장할 구조체이다.
class Point {
private:
float x, y;
public:
Point(const float x, const float y)
: x{ x }, y{y}
{}
};
여기에 만약 극좌표계로 좌표값을 저장하는 생성자가 오버로딩된다면 다음과 같다.
Point(const float r, const float theta)
: x{r*cos(theta)}, y{r*sin(theta)}
{}
문제는 이런 식으로 매개변수 형태가 같은 생성자를 추가하면 컴파일 에러가 뜬다.
이를 위해 좌표계 종류를 구분하는 enum 타입을 파라미터 값에 추가할 수 있다.
enum class PointType {
cartesian,
polar
};
class Point {
...
public:
Point(float a, float b, PointType type = PointType::cartesian) {
if (type == PointType::cartesian) {
x = a;
y = b;
}
else { // (type == PointType::polar)
x = a * cos(b);
y = a * sin(b);
}
}
};
오버로딩에 대한 컴파일 에러는 해결되었지만, 매개변수 명이 (x, y)에서 (a, b)로 변경되었다. 이는 중립적인 이름을 써야하는 부분에 있어 어쩔 수 없는 선택이긴 하지만 생성자의 사용법을 직관적으로 표현하는데 있어 실패한 것이다.
직교 좌표계의 경우 (x, y), 극좌표계의 경우 (r, theta)라고 매개변수 명을 지정한다면 직관적일 수 있을 것이다. 이러한 문제를 팩토리 메서드로 개선할 수 있다.
생성자 자체를 클라이언트에서 호출하지 않게 하고(protected로 생성자를 숨김), 종류에 맞는 Point 객체를 리턴하는 함수를 호출하게 하는 방법이 있다. 이를 위해선 객체를 리턴하는 생성 함수를 static으로 선언하여야 한다.
class Point {
private:
float x, y;
protected:
Point(const float x, const float y)
: x{ x }, y{ y }
{}
public:
// 직교 좌표점을 전달하여 객체 생성
static Point NewCartesian(float x, float y) {
return { x, y }; // 생성자 호출 (유니폼 초기화)
}
// 극 좌표점을 전달하여 객체 생성
static Point NewPolar(float r, float theta) {
return { r * cos(theta), r * sin(theta) };
}
};
바로 이 static 메서드들을 팩토리 메서드하고 부른다. 함수의 이름과 좌표 매개변수의 이름들을 통해 그 의미가 무엇인지, 어떤 값이 인자로 주어져야 하는지 명료해졌다.