Factory Pattern
Part of the Object Oriented Programming section of Coddy's C journey — lesson 55 of 61.
The Factory pattern centralizes object creation into a single function. Instead of scattering malloc and initialization code throughout your program, you call one function that decides what to create and returns a ready-to-use object.
This pattern is especially powerful when combined with polymorphism. A factory can return different concrete types through a common base pointer, hiding the creation details from the caller. The caller just asks for "a shape" and the factory decides whether to build a circle, rectangle, or something else.
Here's a typical factory implementation:
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;
}
}The factory takes an identifier (usually an enum) and uses a switch statement to determine which constructor to call. It returns a Shape* regardless of the actual type created. The caller doesn't need to know about Circle or Rectangle — it just works with the base type:
Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s); // polymorphic call
free_shape(s);This pattern makes adding new types easy: just add a new enum value and a new case in the factory. The rest of your code remains unchanged.
Challenge
EasyLet's build a Pet Factory — a system that creates different types of pets through a single factory function. Instead of scattering creation logic throughout your code, you'll centralize it in one place that decides what kind of pet to create based on an input identifier.
You'll organize your code across three files:
pet.h: Define aPetTypeenum with valuesPET_DOG,PET_CAT, andPET_BIRD. Create a basePetstruct that contains a function pointer forspeak(which takes aconst Pet*and returns nothing). Declare the factory functioncreate_petthat takes aPetTypeand returns aPet*, plus afree_petfunction for cleanup.pet.c: Define three concrete pet structs —Dog,Cat, andBird— each embeddingPetas their first member. Implement a speak function for each type:- Dogs print:
Woof! - Cats print:
Meow! - Birds print:
Tweet!
create_petfactory — use a switch statement on thePetTypeto call the correct constructor and return the result as aPet*. For invalid types, returnNULL. Implementfree_petto release the allocated memory.- Dogs print:
main.c: Read an integer representing the pet type (0 for dog, 1 for cat, 2 for bird). Use your factory to create the appropriate pet, call itsspeakfunction polymorphically through the basePet*pointer, then free the pet.
Your program will receive one input: an integer indicating which pet to create.
Example output when the input is 0:
Woof!Example output when the input is 1:
Meow!Example output when the input is 2:
Tweet!The beauty of the Factory pattern is that main.c doesn't need to know about Dog, Cat, or Bird structs — it only works with the base Pet type. Adding a new pet type later means adding a new enum value and a new case in the factory, without changing any code that uses pets.
Cheat sheet
The Factory pattern centralizes object creation into a single function, hiding creation details from the caller.
A factory function takes an identifier (typically an enum) and uses a switch statement to determine which constructor to call, returning a base type pointer:
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;
}
}The caller works only with the base type, enabling polymorphic behavior:
Shape* s = create_shape(SHAPE_CIRCLE);
s->draw(s); // polymorphic call
free_shape(s);Benefits: Adding new types requires only adding a new enum value and switch case, without changing existing code that uses the factory.
Try it yourself
#include <stdio.h>
#include "pet.h"
int main(void) {
int type;
scanf("%d", &type);
// TODO: Use the factory to create the appropriate pet
// Hint: Cast the int to PetType
// TODO: Call the speak function polymorphically through the Pet* pointer
// TODO: Free the pet
return 0;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Modular Programming Basics
Header FilesInclude GuardsSource FilesStatic FunctionsRecap: Modular Calculator4Encapsulation
Opaque Pointers ConceptDefining Opaque StructsGetters and SettersValidation in SettersRecap: Secret Box2Objects and Methods
Structs as ObjectsThe 'Self' PointerConst CorrectnessPointer vs ValueHelper MethodsRecap: Point Manager5Project: Simple Bank Account
Project SetupImplementation of Account3Object Lifecycle
Constructor PatternDestructor PatternStack InitializationDeep CopyRecap: String Wrapper6Inheritance via Composition
Struct EmbeddingThe First Member RuleAccessing Parent MembersUpcastingRecap: Shape Hierarchy