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
- Enhanced Functionality: The functionality of an object can be enhanced by combining different decorators.
- Avoiding Subclassing: By using composition instead of inheritance, issues caused by simple multi-level classes can be reduced.
- 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.