🧩 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
exportlogic 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
PdfExporterandCsvExporter
- Represented by
-
Decorator: Implements
Componentand wraps additional behavior around anotherComponent- Represented by
LoggingExporter
- Represented by
-
ConcreteDecorator: A decorator that adds specific new behavior
- In this code,
LoggingExporterserves 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.