CODESAMPLE
Composite - C
The Composite pattern allows you to treat individual objects and compositions of objects uniformly. It defines a tree-like structure where each node can be either a leaf (individual object) or a composite (collection of objects). This example demonstrates it with a simple shape hierarchy. Shapes can be individual circles or rectangles, or a group containing other shapes. All shapes have a draw() method, allowing you to iterate through a composite and draw all contained shapes without knowing their specific types. The C implementation utilizes structs and function pointers to achieve polymorphism. The use of structs is idiomatic for grouping data, and function pointers allow for flexible behavior definitions.
#include <stdio.h>
#include <stdlib.h>
// Define the Shape interface
typedef struct Shape Shape;
typedef void (*DrawFunc)(const Shape*);
struct Shape {
DrawFunc draw;
void* data; // Generic data for each shape type
};
// Concrete Shape: Circle
typedef struct Circle Circle;
struct Circle {
int x, y, radius;
};
void circle_draw(const Shape* shape) {
const Circle* circle = (const Circle*)shape->data;
printf("Drawing Circle at (%d, %d) with radius %d\n", circle->x, circle->y, circle->radius);
}
Shape* create_circle(int x, int y, int radius) {
Circle* circle = (Circle*)malloc(sizeof(Circle));
circle->x = x;
circle->y = y;
circle->radius = radius;
Shape* shape = (Shape*)malloc(sizeof(Shape));
shape->draw = circle_draw;
shape->data = circle;
return shape;
}
// Concrete Shape: Rectangle
typedef struct Rectangle Rectangle;
struct Rectangle {
int x, y, width, height;
};
void rectangle_draw(const Shape* shape) {
const Rectangle* rect = (const Rectangle*)shape->data;
printf("Drawing Rectangle at (%d, %d) with width %d and height %d\n", rect->x, rect->y, rect->width, rect->height);
}
Shape* create_rectangle(int x, int y, int width, int height) {
Rectangle* rect = (Rectangle*)malloc(sizeof(Rectangle));
rect->x = x;
rect->y = y;
rect->width = width;
rect->height = height;
Shape* shape = (Shape*)malloc(sizeof(Shape));
shape->draw = rectangle_draw;
shape->data = rect;
return shape;
}
// Composite Shape: ShapeGroup
typedef struct ShapeGroup ShapeGroup;
struct ShapeGroup {
Shape* children[100]; // Fixed size array for simplicity
int count;
};
void shape_group_draw(const Shape* shape) {
const ShapeGroup* group = (const ShapeGroup*)shape->data;
for (int i = 0; i < group->count; i++) {
group->children[i]->draw(group->children[i]);
}
}
Shape* create_shape_group() {
ShapeGroup* group = (ShapeGroup*)malloc(sizeof(ShapeGroup));
group->count = 0;
Shape* shape = (Shape*)malloc(sizeof(Shape));
shape->draw = shape_group_draw;
shape->data = group;
return shape;
}
void add_shape(Shape* group, Shape* shape) {
ShapeGroup* g = (ShapeGroup*)group->data;
g->children[g->count++] = shape;
}
int main() {
Shape* circle1 = create_circle(10, 20, 5);
Shape* circle2 = create_circle(30, 40, 10);
Shape* rect1 = create_rectangle(5, 5, 15, 20);
Shape* group1 = create_shape_group();
add_shape(group1, circle1);
add_shape(group1, circle2);
Shape* group2 = create_shape_group();
add_shape(group2, rect1);
add_shape(group2, group1);
group2->draw(group2);
// Free allocated memory (important!)
free(circle1->data);
free(circle1);
free(circle2->data);
free(circle2);
free(rect1->data);
free(rect1);
free(group1->data);
free(group1);
free(group2->data);
free(group2);
return 0;
}