팩토리 패턴
Coddy C 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 55번째.
팩토리 패턴(Factory pattern)은 객체 생성을 하나의 함수로 중앙 집중화합니다. 프로그램 전체에 malloc과 초기화 코드를 분산시키는 대신, 무엇을 생성할지 결정하고 즉시 사용 가능한 객체를 반환하는 하나의 함수를 호출합니다.
이 패턴은 다형성과 결합될 때 특히 강력합니다. 팩토리는 공통 베이스 포인터를 통해 서로 다른 구체적인 타입들을 반환할 수 있으며, 호출자로부터 생성 세부 사항을 숨깁니다. 호출자는 단지 "a shape"를 요청할 뿐이며, 팩토리가 원, 사각형 또는 다른 것을 생성할지 결정합니다.
다음은 전형적인 팩토리 구현 예시입니다:
typedef enum {
SHAPE_CIRCLE,
SHAPE_RECTANGLE
} ShapeType;
Shape* create_shape(ShapeType type) {
switch (type) {
case SHAPE_CIRCLE:
return (Shape*)create_circle(5.0);
case SHAPE_RECTANGLE:
return (Shape*)create_rectangle(4.0, 3.0);
default:
return NULL;
}
}팩토리는 식별자(보통 열거형)를 받아 switch 문을 사용하여 어떤 생성자를 호출할지 결정합니다. 생성된 실제 타입에 관계없이 Shape*를 반환합니다. 호출자는 Circle이나 Rectangle에 대해 알 필요가 없으며, 단지 기본 타입으로만 작업하면 됩니다:
Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s); // 다형성 호출
free_shape(s);이 패턴은 새로운 타입을 추가하는 것을 쉽게 만듭니다. 새로운 enum 값과 factory에 새로운 case를 추가하기만 하면 됩니다. 나머지 코드는 변경되지 않은 상태로 유지됩니다.
챌린지
쉬움단일 팩토리 함수를 통해 다양한 종류의 반려동물을 생성하는 시스템인 Pet Factory를 만들어 보겠습니다. 생성 로직을 코드 여기저기에 분산시키는 대신, 입력 식별자에 따라 어떤 종류의 반려동물을 생성할지 결정하는 한 곳으로 중앙 집중화합니다.
코드는 다음 세 개의 파일로 구성됩니다:
pet.h:PET_DOG,PET_CAT,PET_BIRD값을 갖는PetType열거형(enum)을 정의합니다.speak(const Pet*를 인자로 받고 반환값이 없음)를 위한 함수 포인터를 포함하는 기본Pet구조체를 생성합니다.PetType을 인자로 받아Pet*를 반환하는 팩토리 함수create_pet과 정리를 위한free_pet함수를 선언합니다.pet.c:Pet을 첫 번째 멤버로 포함하는 세 개의 구체적인 반려동물 구조체인Dog,Cat,Bird를 정의합니다. 각 타입에 대해 speak 함수를 구현합니다:- Dogs 출력:
Woof! - Cats 출력:
Meow! - Birds 출력:
Tweet!
create_pet팩토리를 구현합니다.PetType에 대해 switch 문을 사용하여 올바른 생성자를 호출하고 결과를Pet*로 반환합니다. 유효하지 않은 타입의 경우NULL을 반환합니다. 할당된 메모리를 해제하는free_pet을 구현합니다.- Dogs 출력:
main.c: 반려동물 타입을 나타내는 정수(0은 dog, 1은 cat, 2는 bird)를 읽습니다. 팩토리를 사용하여 적절한 반려동물을 생성하고, 기본Pet*포인터를 통해 다형적으로speak함수를 호출한 다음 반려동물 메모리를 해제합니다.
프로그램은 생성할 반려동물을 나타내는 정수 하나를 입력받습니다.
입력이 0일 때의 출력 예시:
Woof!입력이 1일 때의 출력 예시:
Meow!입력이 2일 때의 출력 예시:
Tweet!팩토리 패턴의 장점은 main.c가 Dog, Cat, Bird 구조체에 대해 알 필요가 없다는 것입니다. 오직 기본 Pet 타입으로만 동작합니다. 나중에 새로운 반려동물 타입을 추가하려면 반려동물을 사용하는 코드를 수정할 필요 없이, 새로운 열거형 값과 팩토리에 새로운 case를 추가하기만 하면 됩니다.
치트 시트
팩토리 패턴(Factory pattern)은 객체 생성을 단일 함수로 중앙 집중화하여, 호출자로부터 생성 세부 사항을 숨깁니다.
팩토리 함수는 식별자(일반적으로 열거형)를 인자로 받아 switch 문을 사용하여 어떤 생성자를 호출할지 결정하고, 기본 타입 포인터를 반환합니다:
typedef enum {
SHAPE_CIRCLE,
SHAPE_RECTANGLE
} ShapeType;
Shape* create_shape(ShapeType type) {
switch (type) {
case SHAPE_CIRCLE:
return (Shape*)create_circle(5.0);
case SHAPE_RECTANGLE:
return (Shape*)create_rectangle(4.0, 3.0);
default:
return NULL;
}
}호출자는 기본 타입으로만 작업하므로 다형성 동작이 가능해집니다:
Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s); // polymorphic call
free_shape(s);장점: 새로운 타입을 추가할 때 팩토리를 사용하는 기존 코드를 변경하지 않고도, 새로운 열거형 값과 switch 케이스만 추가하면 됩니다.
직접 해보기
#include <stdio.h>
#include "pet.h"
int main(void) {
int type;
scanf("%d", &type);
// TODO: 팩토리를 사용하여 적절한 pet을 생성하세요
// Hint: int를 PetType으로 캐스팅하세요
// TODO: Pet* 포인터를 통해 다형적으로 speak 함수를 호출하세요
// TODO: pet을 메모리 해제하세요
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.