Bridge Software Pattern C Examples

The Bridge pattern in C allows you to separate an abstraction from its implementation, allowing them to vary independently. Here are three examples of implementing the Bridge pattern in C:

Table of Contents

Example 1: Basic Bridge Pattern

#include <stdio.h>

// Implementor interface
typedef struct {
    void (*operationImp)(void);
} Implementor;

void implementorOperation(Implementor* implementor) {
    implementor->operationImp();
}

// Concrete Implementors
void concreteImplementorAOperation(void) {
    printf("Concrete Implementor A operation\n");
}

void concreteImplementorBOperation(void) {
    printf("Concrete Implementor B operation\n");
}

// Abstraction
typedef struct {
    Implementor implementor;
    void (*operation)(void);
} Abstraction;

void abstractionOperation(Abstraction* abstraction) {
    printf("Abstraction operation\n");
    abstraction->operation(&abstraction->implementor);
}

// Refined Abstractions
void refinedAbstraction1Operation(Implementor* implementor) {
    printf("Refined Abstraction 1 operation\n");
    implementorOperation(implementor);
}

void refinedAbstraction2Operation(Implementor* implementor) {
    printf("Refined Abstraction 2 operation\n");
    implementorOperation(implementor);
}

int main() {
    Implementor implementorA = {concreteImplementorAOperation};
    Implementor implementorB = {concreteImplementorBOperation};

    Abstraction abstraction1 = {implementorA, refinedAbstraction1Operation};
    Abstraction abstraction2 = {implementorB, refinedAbstraction2Operation};

    abstractionOperation(&abstraction1);
    abstractionOperation(&abstraction2);

    return 0;
}

In this C example, we have an Implementor interface, concrete implementors concreteImplementorAOperation and concreteImplementorBOperation, an Abstraction interface, and refined abstractions refinedAbstraction1Operation and refinedAbstraction2Operation. The Bridge pattern allows different abstractions to work with different implementors.

Example 2: Bridge Pattern with Function Pointers

#include <stdio.h>

// Implementor interface
typedef struct {
    void (*operationImp)(void);
} Implementor;

void implementorOperation(Implementor* implementor) {
    implementor->operationImp();
}

// Concrete Implementors
void concreteImplementorAOperation(void) {
    printf("Concrete Implementor A operation\n");
}

void concreteImplementorBOperation(void) {
    printf("Concrete Implementor B operation\n");
}

// Abstraction
typedef struct {
    Implementor implementor;
    void (*operation)(void);
} Abstraction;

void abstractionOperation(Abstraction* abstraction) {
    printf("Abstraction operation\n");
    abstraction->operation(&abstraction->implementor);
}

// Refined Abstractions
void refinedAbstraction1Operation(Implementor* implementor) {
    printf("Refined Abstraction 1 operation\n");
    implementorOperation(implementor);
}

void refinedAbstraction2Operation(Implementor* implementor) {
    printf("Refined Abstraction 2 operation\n");
    implementorOperation(implementor);
}

int main() {
    Implementor implementorA = {concreteImplementorAOperation};
    Implementor implementorB = {concreteImplementorBOperation};

    Abstraction abstraction1 = {implementorA, refinedAbstraction1Operation};
    Abstraction abstraction2 = {implementorB, refinedAbstraction2Operation};

    abstractionOperation(&abstraction1);
    abstractionOperation(&abstraction2);

    return 0;
}

This C example uses function pointers to implement the Bridge pattern, allowing abstractions to work with different implementors through function calls.

Example 3: Bridge Pattern with Data Structures

#include <stdio.h>

// Implementor interface
typedef struct {
    void (*operationImp)(void*);
} Implementor;

void implementorOperation(Implementor* implementor, void* data) {
    implementor->operationImp(data);
}

// Concrete Implementors
typedef struct {
    char data[50];
} ImplementorAData;

void concreteImplementorAOperation(void* data) {
    ImplementorAData* aData = (ImplementorAData*)data;
    printf("Concrete Implementor A operation with data: %s\n", aData->data);
}

typedef struct {
    int value;
} ImplementorBData;

void concreteImplementorBOperation(void* data) {
    ImplementorBData* bData = (ImplementorBData*)data;
    printf("Concrete Implementor B operation with data: %d\n", bData->value);
}

// Abstraction
typedef struct {
    Implementor implementor;
    void (*operation)(void*);
} Abstraction;

void abstractionOperation(Abstraction* abstraction, void* data) {
    printf("Abstraction operation\n");
    abstraction->operation(&abstraction->implementor, data);
}

// Refined Abstractions
void refinedAbstraction1Operation(Implementor* implementor, void* data) {
    printf("Refined Abstraction 1 operation\n");
    implementorOperation(implementor, data);
}

void refinedAbstraction2Operation(Implementor* implementor, void* data) {
    printf("Refined Abstraction 2 operation\n");
    implementorOperation(implementor, data);
}

int main() {
    Implementor implementorA = {concreteImplementorAOperation};
    Implementor implementorB = {concreteImplementorBOperation};

    Abstraction abstraction1 = {implementorA, refinedAbstraction1Operation};
    Abstraction abstraction2 = {implementorB, refinedAbstraction2Operation};

    ImplementorAData aData = {"Data for Implementor A"};
    ImplementorBData bData = {42};

    abstractionOperation(&abstraction1, &aData);
    abstractionOperation(&abstraction2, &bData);

    return 0;
}

In this C example, we use data structures as the implementors’ input. This allows different implementors to operate on different data types while maintaining a common abstraction.

Dane Stuckel Photo
Written and maintained by Dane Stuckel.
To like, comment or give feedback,
please share on social media.
Follow the author for more content like this.