概要
Adapter(アダプター)パターンは、
本来互換性のないインターフェース同士を、ラッパー(Adapter)を介して接続可能にする構造的パターンである。
異なるライブラリ・API・クラスを統一的に扱いたいときに、既存コードを変更せずに一貫した使用方法を提供できるのが特徴。
1. なぜAdapterが必要か?
❌ API仕様の違いを都度対応して使い分ける構造
a.read_csv()
b.load_from_csv()
→ 呼び出し元に多くの条件分岐や仕様知識が必要になる
✅ アダプターを使って統一的なインターフェースに変換
reader = CSVReaderAdapter(b)
reader.read()
→ 呼び出し元は一貫したメソッドで異なるクラスを扱える
2. 基本構造
✅ Target(期待されるインターフェース)
class Reader:
def read(self):
raise NotImplementedError
✅ Adaptee(既存の異なるインターフェース)
class LegacyCSV:
def load_from_csv(self):
print("Loading CSV using legacy method.")
✅ Adapter(インターフェース変換)
class CSVReaderAdapter(Reader):
def __init__(self, legacy_csv: LegacyCSV):
self._legacy_csv = legacy_csv
def read(self):
self._legacy_csv.load_from_csv()
✅ 使用例
legacy = LegacyCSV()
adapter = CSVReaderAdapter(legacy)
adapter.read()
出力:
Loading CSV using legacy method.
3. Python的応用:Duck Typingで柔軟なAdapter実装
class JSONLoader:
def load_json(self):
return {"data": "value"}
class JSONAdapter:
def __init__(self, adaptee):
self._adaptee = adaptee
def read(self):
return self._adaptee.load_json()
→ インターフェースに厳密に準拠せずとも、read() さえ提供すれば動く構造
4. 実務ユースケース
✅ 複数ライブラリ間のAPIインターフェース統一
→ 仕様の異なるクラス群を一つの呼び出しインターフェースに変換
✅ レガシーシステムと新システムの接続
→ 古いクラス群を新仕様に適応させるブリッジとして活用
✅ ユニットテスト用のモック・スタブ生成
→ テスト対象と同じインターフェースを持つテストダブルの注入
✅ 外部APIクライアントの抽象化
→ バージョンや仕様変更に対応するためのアダプター層の挿入
5. よくある誤用と対策
❌ Adapteeを変更してしまう
→ ✅ Adapterの意義は「既存コードを一切変更しない」ことにある
❌ アダプターが多すぎて構造が煩雑に
→ ✅ 同じパターンを繰り返す場合はファクトリ or メタクラスで集約
❌ 使用者がAdapterを意識しすぎる実装
→ ✅ 使用側は「一貫したインターフェース」だけに依存する構造に
結語
Adapterパターンとは、“異なる世界を接続する通訳者”のような存在である。
- インターフェースの不一致をラッパーとして包み込み、互換性を提供
- 既存クラスを変更せず、新しい文脈でも自然に利用可能にする
- Pythonでは型より動作(Duck Typing)を重視することで、非常に柔軟にAdapterを設計可能
Pythonicとは、“差異を包み、統一の中に調和を築く”こと。
Adapterパターンはその融合を、コードの層で静かに実現する技法である。