From grimoire
Adds runtime object responsibilities via wrapping (Decorator pattern). Applies to OOP codebases, especially Java I/O streams, Python decorators, and Django middleware.
How this skill is triggered — by the user, by Claude, or both
Slash command
/grimoire:apply-decorator-patternThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Attach additional responsibilities to an object dynamically by wrapping it in decorator objects that share the same interface.
Attach additional responsibilities to an object dynamically by wrapping it in decorator objects that share the same interface.
Adopted by: Java I/O (BufferedInputStream(new FileInputStream(path)) is a
decorator chain — used in virtually every Java file operation), Python's @functools.wraps
and the entire decorator syntax (@, @login_required, @cache — one of Python's most
distinctive features), Django's middleware stack (each middleware wraps the next,
adding auth, CSRF, session handling), and JavaScript's Array.prototype.reduce
-based pipeline patterns.
Impact: Java's I/O library design is cited in GoF as the canonical Decorator
example. Without Decorator, adding buffering + gzip + encryption to file I/O would
require 3×3=9 dedicated subclasses for each combination. With Decorator, any combination
is achieved by wrapping: 3 decorators compose into any of 9 behaviors with 3 classes.
Why best: Subclassing for each combination is the alternative — it produces
exponential class growth (M features × N base types). Decorator provides the same
flexibility from M+N classes with runtime composition.
Sources: Gamma et al. (1994) pp. 175–184; Python functools documentation;
Django middleware documentation
from abc import ABC, abstractmethod
class TextProcessor(ABC):
@abstractmethod
def process(self, text: str) -> str: ...
class PlainTextProcessor(TextProcessor):
def process(self, text: str) -> str:
return text
class TextProcessorDecorator(TextProcessor):
def __init__(self, wrapped: TextProcessor):
self._wrapped = wrapped
def process(self, text: str) -> str:
return self._wrapped.process(text)
class UpperCaseDecorator(TextProcessorDecorator):
def process(self, text: str) -> str:
return super().process(text).upper()
class TrimDecorator(TextProcessorDecorator):
def process(self, text: str) -> str:
return super().process(text).strip()
class PrefixDecorator(TextProcessorDecorator):
def __init__(self, wrapped: TextProcessor, prefix: str):
super().__init__(wrapped)
self._prefix = prefix
def process(self, text: str) -> str:
return f"{self._prefix}{super().process(text)}"
processor = PrefixDecorator(
UpperCaseDecorator(
TrimDecorator(PlainTextProcessor())
),
prefix=">> "
)
print(processor.process(" hello world "))
# >> HELLO WORLD
Order matters: decorators apply from innermost to outermost. Trim before UpperCase is different from UpperCase before Trim only if case affects whitespace — but always be explicit about order.
@ syntax and functools handle function-level decoration natively. Use them directly rather than building class-based decorators for functions.Decorator that doesn't call super().process() — a decorator that forgets to delegate completely replaces the wrapped behavior instead of extending it. Every decorator must call its wrapped component unless replacement is intentional.
Breaking the interface contract. A decorator may not add, remove, or change the signature of methods on the interface. It wraps, not transforms. Interface changes belong in Adapter.
Using Decorator when Strategy is the right tool. If the variation is selecting one algorithm from several alternatives (not stacking multiple behaviors), apply-strategy-pattern is cleaner.
npx claudepluginhub jeffreytse/grimoire --plugin grimoire2plugins reuse this skill
First indexed Jun 9, 2026
Attaches additional behaviors to objects at runtime by wrapping them in decorator objects. Useful for stacking cross-cutting concerns like logging, caching, validation, or retry without subclassing.
Generates Decorator pattern for PHP 8.4: interface, abstract decorator, concrete decorators (logging, caching, metrics, transactional), optional factory, and unit tests. For dynamic behavior without inheritance.
Converts incompatible class interfaces so they work together, wrapping legacy or third-party code without modifying it. Useful when integrating code with mismatched APIs.