🧩 Decorator パターン
✅ 設計意図
- 処理に追加の振る舞いをラップして重ねる構造
- 継承ではなく「合成」で振る舞いを追加できる
✅ 適用理由
- 元の
export
処理を変えずにログ機能を追加 - 追加機能を柔軟に組み合わせ可能
✅ 向いているシーン
- ログ・バリデーション・権限チェックなど、横断的な処理を再利用したい
✅ コード例
- 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("ユーザー一覧")
✅ 解説
このコードは Decorator
パターン を使用して、既存の機能(データ出力)に追加の機能(ログ出力)を動的に付加する設計を実現している。
Decorator
パターンは、オブジェクトに動的に責務を追加する柔軟な方法を提供するデザインパターンであり、継承を使わずに機能を拡張できる。
1. Decorator パターンの概要
- Component: 基本機能を定義する共通インターフェース
- このコードでは
Exporter
が該当
- このコードでは
- ConcreteComponent: Component を実装し、基本機能を提供するクラス
- このコードでは
PdfExporter
とCsvExporter
が該当
- このコードでは
- Decorator:
Component
を実装し、基本機能に追加の機能を付加するクラス- このコードでは
LoggingExporter
が該当
- このコードでは
- ConcreteDecorator:
Decorator
を拡張して、具体的な追加機能を提供するクラス- このコードでは
LoggingExporter
がその役割を担う
- このコードでは
2. 主なクラスとその役割
Exporter
- 基本機能を定義するインターフェース
export(data: string): void
メソッドを定義
PdfExporter
,CsvExporter
Exporter
を実装した具体的なコンポーネント- PDF または CSV 形式でデータを出力
LoggingExporter
- Decorator クラス
- Exporter をラップし、データ出力の前後にログ出力を追加
3. UML クラス図
4. Decorator パターンの利点
- 動的な機能追加: 継承を使わずに、既存のオブジェクトに動的に機能を追加可能
- 柔軟性: 複数のデコレータを組み合わせて機能を拡張可能
- オープン/クローズド原則: 既存のクラスを変更せずに機能を拡張可能
この設計は、既存の機能に追加の責務を柔軟に付加する必要がある場面で非常に有効であり、コードの再利用性と拡張性を向上させる。