Decorator Pattern: Implementation and Advantages in C Language

Decorator Pattern: Implementation and Advantages in C Language

The Decorator Pattern is a structural design pattern that allows adding new functionality to existing objects without altering their structure. This flexible design enables programmers to dynamically add additional responsibilities or behaviors to an object at runtime. The decorator pattern is particularly important when there is a need to extend common classes without affecting other objects.

Advantages of the Decorator Pattern

  1. Enhanced Functionality: The functionality of an object can be enhanced by combining different decorators.
  2. Avoiding Subclassing: By using composition instead of inheritance, issues caused by simple multi-level classes can be reduced.
  3. Flexibility: Functions can be freely added or removed at runtime based on requirements.

Use Cases

  • In GUI frameworks, providing additional responsibilities (such as borders or scroll bars) to basic components (like windows or buttons).
  • In data stream processing pipelines, implementing different data input and output formats.

Implementation in C Language

Although C is a procedural programming language, we can still simulate the decorator pattern using structures and function pointers. Below is a simple example that demonstrates how to use the decorator pattern to add additional effects to text output, such as converting to uppercase and adding prefix/suffix text.

Step 1: Define the Basic Component

First, we define an interface, which is our basic component. In C, this is typically represented as a structure with function pointers. Here we define <span>TextComponent</span> to represent text output:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Define text component
typedef struct TextComponent {
    void (*print)(struct TextComponent* this);
    char* text;
} TextComponent;

void print_text(TextComponent* this) {
    printf("%s", this->text);
}

// Create a text component based on a string
TextComponent* create_text_component(const char* text) {
    TextComponent* component = (TextComponent*)malloc(sizeof(TextComponent));
    component->text = strdup(text);
    component->print = print_text;
    return component;
}

Step 2: Create the Decorator

Next, we create a decorator that wraps around <span>TextComponent</span>. For example, a decorator that converts the text to uppercase:

// Declare uppercase character conversion type for wrapping original text
typedef struct UppercaseDecorator {
    TextComponent base; // Base component
} UppercaseDecorator;

// Rewrite the print method to print in uppercase
void uppercase_print(TextComponent* this) {
    for (int i = 0; i < strlen(this->text); i++) {
        putchar(toupper(this->text[i]));
    }
}

// Wrap the base component with uppercase printing logic
UppercaseDecorator* create_uppercase_decorator(TextComponent* component) {
    UppercaseDecorator *decorator = (UppercaseDecorator*)malloc(sizeof(UppercaseDecorator));
    decorator->base.text = strdup(component->text); // Copy base text content
    // Replace the print method to implement uppercase
    decorator->base.print = uppercase_print;
    return decorator;
}

Step 3: Using Components and Decorators

Now, let’s see how everything works together, including how to combine these elements and execute them:

int main() {
    // Create a normal text component
    TextComponent *component1 = create_text_component("Hello, World!\n");
    printf("Normal Output:\n");
    component1->print(component1); // Output unchanged content
    printf("\n");
    // Create and apply uppercase decorator:
    UppercaseDecorator *decorator1 = create_uppercase_decorator(component1);
    printf("Decorated Output:\n");
    decorator1->base.print((TextComponent*)decorator1); // Output modified content
    free(component1->text);
    free(decorator1->base.text);
    free(component1);
    free(decorator1);
    return 0;
}

Conclusion

In this code, we created a basic <span>Text Component</span> class and then used the <span>UpperCase Decorator</span> to display it in uppercase. This way, functionality can be extended without fundamentally changing the original class, which aligns well with the “Open/Closed Principle.”

We hope this example provides you with a deeper understanding of the decorator pattern in C language. For further learning, try implementing other types of decorators based on different requirements.

Leave a Comment