概要
Adapter(アダプター)パターンは、
既存のクラスやコードのインターフェースをクライアントの期待する形に変換するための構造的デザインパターンである。
このパターンを使うことで、互換性のないインターフェース同士を繋ぎ、既存コードを再利用しやすくすることができる。
1. なぜAdapterが必要か?
❌ クライアントが期待するメソッド名と既存APIが合わない
# クライアントは .request() を期待
# しかし実装クラスは .specific_request() を持つ
→ 名前や引数が異なることで、既存コードを再利用できない
✅ Adapterでクライアントに合わせたインターフェースを提供
adapter = Adapter(LegacySystem())
adapter.request()
→ インターフェースを変換して、透明に利用可能にする
2. 基本構造
✅ Target(クライアントが期待するインターフェース)
class Target:
def request(self):
raise NotImplementedError
✅ Adaptee(既存の実装)
class LegacySystem:
def specific_request(self):
return "結果:レガシーAPI呼び出し"
✅ Adapter(変換ラッパー)
class Adapter(Target):
def __init__(self, adaptee: LegacySystem):
self.adaptee = adaptee
def request(self):
result = self.adaptee.specific_request()
print(f"変換されたインターフェース: {result}")
✅ 使用例
legacy = LegacySystem()
adapter = Adapter(legacy)
adapter.request()
# → 変換されたインターフェース: 結果:レガシーAPI呼び出し
3. Python的応用:dictをクラスAPIに変換
class DictAdapter:
def __init__(self, data):
self._data = data
def get_name(self):
return self._data.get("name")
def get_age(self):
return self._data.get("age")
data = {"name": "Alice", "age": 30}
user = DictAdapter(data)
print(user.get_name()) # Alice
→ 動的構造(辞書やJSON)をクラスAPIとして扱うことで柔軟性と型安全性を両立
4. 実務ユースケース
✅ 外部ライブラリやレガシーコードのラップ
→ 期待するインターフェースと合わないライブラリを適応して利用可能に
✅ APIレスポンス(JSON)のデータ構造変換
→ API仕様に依存せず、統一された内部インターフェースを提供
✅ デザイン変更時の互換レイヤー構築
→ 新旧のクラスを並行稼働させる中間層としてAdapterを活用
✅ テスト用のモック・スタブとして既存APIを再利用
→ クライアントコードを変更せず、テスト対象を差し替え可能に
5. よくある誤用と対策
❌ Adapterが過度にロジックを持つ
→ ✅ Adapterは変換のみに責任を持つべきであり、処理はAdapteeに委ねる
❌ Adapteeに手を加えて対応しようとする
→ ✅ 既存コードには変更を加えず、Adapterで対応するのが前提
❌ Adapterが複数の責務を抱える
→ ✅ 単一の変換目的ごとにAdapterを設計し、責務を分離する
結語
Adapterパターンとは、“合わない形を無理に変えるのではなく、インターフェースを通訳する構造設計”である。
- 名前や構造の不一致を、変換クラスで吸収することで再利用性を高める
- 特に既存コードや外部ライブラリと連携する際の、境界インターフェースとして機能
- Pythonでは柔軟なDuck Typingを活かし、静的型言語に比べてAdapterの導入がより直感的に可能
Pythonicとは、“現実のギャップをコードで吸収し、構造の統一を図る”ことであり、
Adapterパターンはその接続性と柔軟性を、実装の中に美しく融合させる技法である。