🧩 Decorator Pattern
✅ Intent
- Wrap additional behavior around an existing process in a layered structure
- Add functionality through composition, not inheritance
✅ Motivation
- Add logging to the existing
export
logic without modifying it - Additional behaviors can be combined flexibly
✅ When to Use
- When you want to reuse cross-cutting concerns like logging, validation, or permission checks
✅ Code Example
- TypeScript
- PHP
- Python
// コンポーネントインターフェース
interface Exporter {
export(data: string): void;
}
// 具象コンポーネント
class PdfExporter implements Exporter {
export(data: string): void {
console.log(`PDF出力: ${data}`);
}
}
class CsvExporter implements Exporter {
export(data: string): void {
console.log(`CSV出力: ${data}`);
}
}
// デコレータ(共通機能)
class LoggingExporter implements Exporter {
constructor(private wrapped: Exporter) {}
export(data: string): void {
console.log("開始ログ");
this.wrapped.export(data);
console.log("完了ログ");
}
}
// 利用例
const pdf = new LoggingExporter(new PdfExporter());
pdf.export("帳票データ");
const csv = new LoggingExporter(new CsvExporter());
csv.export("ユーザー一覧");
<?php
interface Exporter {
public function export(string $data): void;
}
class PdfExporter implements Exporter {
public function export(string $data): void {
echo "PDF出力: {$data}\n";
}
}
class CsvExporter implements Exporter {
public function export(string $data): void {
echo "CSV出力: {$data}\n";
}
}
class LoggingExporter implements Exporter {
public function __construct(private Exporter $wrapped) {}
public function export(string $data): void {
echo "開始ログ\n";
$this->wrapped->export($data);
echo "完了ログ\n";
}
}
// 利用例
$pdf = new LoggingExporter(new PdfExporter());
$pdf->export("帳票データ");
$csv = new LoggingExporter(new CsvExporter());
$csv->export("ユーザー一覧");
from abc import ABC, abstractmethod
class Exporter(ABC):
@abstractmethod
def export(self, data: str):
pass
class PdfExporter(Exporter):
def export(self, data: str):
print(f"PDF出力: {data}")
class CsvExporter(Exporter):
def export(self, data: str):
print(f"CSV出力: {data}")
class LoggingExporter(Exporter):
def __init__(self, wrapped: Exporter):
self._wrapped = wrapped
def export(self, data: str):
print("開始ログ")
self._wrapped.export(data)
print("完了ログ")
# 利用例
pdf = LoggingExporter(PdfExporter())
pdf.export("帳票データ")
csv = LoggingExporter(CsvExporter())
csv.export("ユーザー一覧")
✅ Explanation
This code applies the Decorator
pattern to dynamically add additional functionality (logging)
to an existing feature (data export).
The Decorator
pattern allows responsibilities to be added to objects at runtime without modifying their structure,
providing a flexible alternative to subclassing.
1. Overview of the Decorator Pattern
-
Component: Defines the common interface for the core functionality
- Represented by
Exporter
- Represented by
-
ConcreteComponent: Implements the base functionality
- Represented by
PdfExporter
andCsvExporter
- Represented by
-
Decorator: Implements
Component
and wraps additional behavior around anotherComponent
- Represented by
LoggingExporter
- Represented by
-
ConcreteDecorator: A decorator that adds specific new behavior
- In this code,
LoggingExporter
serves this role
- In this code,
2. Key Classes and Their Roles
-
Exporter
- Interface defining the export behavior
- Declares the method
export(data: string): void
-
PdfExporter
,CsvExporter
- Concrete components implementing
Exporter
- Export data in PDF or CSV format
- Concrete components implementing
-
LoggingExporter
- A decorator class that wraps an
Exporter
- Adds logging before and after the export operation
- A decorator class that wraps an
3. UML Class Diagram
4. Benefits of the Decorator Pattern
- Dynamic Feature Extension: Add functionality without modifying existing classes
- Flexibility: Combine multiple decorators to layer behaviors
- Open/Closed Principle: Extend behavior without altering existing code
This design is highly effective when you need to flexibly enhance functionality at runtime,
improving code reusability and extensibility.