Design Pattern Examples
Overview of object-oriented design patterns
Decorator Pattern

Diagram of the decorator pattern

The decorator pattern provides a way to extend capabilities to an instance of a class without altering the original class. The intention is to extend the capabilities at runtime, providing a dynamic and potentially user-driven level of extension. This is done by having the decorators provide the same interface as the object being decorated. that way, the decorators can wrap the object or other decorators and still look like the same kind of object to the calling entity.

This kind of architecture requires cooperation among all the decorators and classes being decorated by having each class implement the same abstract interface (again, so all the classes look the same to each other). The decorators then wrap any object with the same abstract interface. The ability of decorators being able to wrap other decorators automatically builds a kind of nested hierarchy, similar to a Composite pattern except that the decorators don't typically support multiple children in a single decorator.

Since each decorator looks like any other decorator (of the same kind), the decorators need to be designed to work in pretty much any order, with the core or concrete class taking whatever parameters it needs to be instantiated (by definition, the concrete class does not take a decorator; decorators are applied to the concrete class by wrapping the concrete class).

How to Use

Links to the Decorator classes
C++ C# Python C
IRenderElement interface IRenderElement interface IRenderElement interface Not Applicable
TextElement class TextElement class TextElement class DynamicString structure
Decorator base class Decorator base class Decorator base class _Decorate() function
WhiteBackgroundDecorator derived class WhiteBackgroundDecorator derived class WhiteBackgroundDecorator derived class WhiteBackgroundDecorator() function
UnderlineDecorator derived class UnderlineDecorator derived class UnderlineDecorator derived class UnderlineDecorator() function
RedForegroundDecorator derived class RedForegroundDecorator derived class RedForegroundDecorator derived class RedForegroundDecorator() function

In this example, the concrete class is called TextElement and up to three decorators can be applied (WhiteBackgroundDecorator, UnderlineDecorator, and RedForegroundDecorator). Decorators should ideally be designed to be applied in any order, as is the case here. If an order is required, the documentation that comes with the decorators would explain it. All decorators implement a base class that manages the wrapped elements (and implements the IRenderElement interface) and the TextElement class just implements the IRenderElement interface.

C++

void Decorator_Exercise()
{
std::cout << std::endl;
std::cout << "Decorator Exercise" << std::endl;
IRenderElement::shared_ptr_t baseElement;
baseElement = std::make_shared<TextElement>("This is raw text");
// Wrap the base element in three decorators.
IRenderElement::shared_ptr_t wrappedElement =
std::make_shared<WhiteBackgroundDecorator>(
std::make_shared<UnderlineDecorator>(
std::make_shared<RedForegroundDecorator>(baseElement)));
// Now render the elements to the console.
std::cout
<< Helpers::formatstring(" base Text element: \"%s\"", baseElement->Render().c_str())
<< std::endl;
std::cout
<< Helpers::formatstring(" Decorated element: \"%s\"", wrappedElement->Render().c_str())
<< std::endl;
std::cout << " Done." << std::endl;
}
std::string formatstring(const char *fmt,...)
Use the given string and arguments to return a buffer containing the formatted string....

C#

public void Run()
{
Console.WriteLine();
Console.WriteLine("Decorator Exercise");
IRenderElement baseElement = new TextElement("This is raw text");
// Wrap the base element in three decorators.
IRenderElement wrappedElement =
new RedForegroundDecorator(baseElement)));
// Now render the elements to the console.
Console.WriteLine(" base Text element: \"{0}\"", baseElement.Render());
Console.WriteLine(" Decorated element: \"{0}\"", wrappedElement.Render());
Console.WriteLine(" Done.");
}
DynamicString * UnderlineDecorator(DynamicString *s)
Represents the Underline decorator, which alters the wrapped content to render it as underlined.
DynamicString * RedForegroundDecorator(DynamicString *s)
Represents the RedForeground decorator, which alters the wrapped content to render as red text.
DynamicString * WhiteBackgroundDecorator(DynamicString *s)
Represents the WhiteBackground decorator, which alters the wrapped content to render the background c...

Python

def Decorator_Exercise():
print()
print("Decorator Exercise")
baseElement = TextElement("This is raw text")
# Wrap the base element in three decorators.
wrappedElement = \
)
)
# Now render the elements to the console.
print(" base Text element: \"{0}\"".format(baseElement.Render()))
print(" Decorated element: \"{0}\"".format(wrappedElement.Render()))
print(" Done.")

C

void Decorator_Exercise(void)
{
printf("\nDecorator_Exercise\n");
const char* text = "This is raw text";
DynamicString string;
DynamicString_Set(&string, text);
// Wrap the base element in three decorators.
DynamicString* rendering = NULL;
printf(" Base Text element: \"%s\"\n", text);
printf(" Decorated element: \"%s\"\n", rendering->string);
printf(" Done.\n");
}
void DynamicString_Clear(DynamicString *string)
Clear a DynamicString object, releasing any allocated memory. Resets to an empty string.
Definition: dynamicstring.c:27
void DynamicString_Initialize(DynamicString *string)
Initialize a DynamicString object to an empty string.
Definition: dynamicstring.c:15
bool DynamicString_Set(DynamicString *string, const char *s)
Set the DynamicString object to the specified string, replacing whatever is in the DynamicString obje...
Definition: dynamicstring.c:73
Represents a string that can be grown dynamically.
Definition: dynamicstring.h:16
char * string
The string that can grow.
Definition: dynamicstring.h:17

Rust

(Apologies. Doxygen does not understand Rust syntax and therefore cannot colorize the code.)

pub fn decorator_exercise() -> Result<(), String> {
println!("");
println!("Decorator Exercise");
let base_element = TextElement::new("This is raw text");
// Wrap the base element in three decorators.
let mut wrapped_element = WhiteBackgroundDecorator::new(base_element.clone());
wrapped_element = UnderlineDecorator::new(wrapped_element.clone());
wrapped_element = RedForegroundDecorator::new(wrapped_element.clone());
// Now render the elements to the console.
println!(" base Text element: \"{}\"", base_element.render());
println!(" Decorated element: \"{}\"", wrapped_element.render());
println!(" Done.");
Ok(())
}

See Also