Menu
Coddy logo textTech

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 icon

Challenge

Easy

Let'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 a PetType enum with values PET_DOG, PET_CAT, and PET_BIRD. Create a base Pet struct that contains a function pointer for speak (which takes a const Pet* and returns nothing). Declare the factory function create_pet that takes a PetType and returns a Pet*, plus a free_pet function for cleanup.
  • pet.c: Define three concrete pet structs — Dog, Cat, and Bird — each embedding Pet as their first member. Implement a speak function for each type:
    • Dogs print: Woof!
    • Cats print: Meow!
    • Birds print: Tweet!
    Create constructor functions for each pet type that allocate memory and wire up the appropriate speak function. Then implement the create_pet factory — use a switch statement on the PetType to call the correct constructor and return the result as a Pet*. For invalid types, return NULL. Implement free_pet to release the allocated memory.
  • 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 its speak function polymorphically through the base Pet* 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;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming