GoF本 Adapter
ねらい
既存クラスのインタフェースを変える
別名
Wrapper
モチベーション
- 既製品の汎用クラスのインタフェースが合わず、フレームワークで使えなかったり、アプリケーションのクラスと互換性がなかったりする
- 汎用クラス自体を書き換えるのは現実的でない
- ソースコードを持っている必要がある
- 汎用なのに、特定のアプリケーションのインタフェースに合わせるべきではない
- 汎用クラスのインタフェースだけ変えればよい
- やり方が2通りある
- 継承方式
- 集約方式
つかいどころ
- あるクラスのインタフェースを変えて、他のクラスとの互換性をもたせたい
- 【集約方式】インタフェースを変えたい側(Adaptee)が独立して継承ツリーをもっている
- 継承方式ではサブクラスまでAdaptできない
- できなくはないけどAdapter派生まみれになるからやめたほうがいい
- 継承方式ではサブクラスまでAdaptできない
構造
登場人物
- Target
- 満たすべきインタフェース
- Client
- Targetインタフェースに依存するクラス
- Adaptee
- Targetインタフェースとインタフェースの合わないクラス
- これにTarget互換をもたせたい
- Adapter
- AdapteeをTarget互換にするためのクラス
- Target派生orTargetを実装するクラス
クライアントコードからの利用
- ClientはAdapterをTargetとして利用する
功罪
継承方式と集約方式とのトレードオフ
継承 | 集約 | |
---|---|---|
Adapteeとの関係 | Adapteeを継承 | Adapteeオブジェクトを集約 |
Adaptee派生クラス対応 | 不可 | 可 |
Adapteeのオーバライド | 可 | 不可 |
間接層 | 増えない | 増える(Adapteeメンバ) |
ほか、考えるべきこと
- AdapteeをTarget互換にするためのAdapterの仕事量はさまざま
- もともと似てれば大したことはしない
- メソッド名の読み替えとか
- 引数の順番を変えるだとか
- 欠けている機能を補うだとかは重い
- もともと似てれば大したことはしない
- Pluggable adapters
- 汎用モジュールの提供を想定
- ユーザが
Adapter
を実装しさえすれば、任意のAdaptee
を使えるつくりにする
- 2-way adapters
Adaptee
として透過性を残すTarget
互換にしつつ、Adaptee
のインタフェースも残すということ
Adaptee
のインタフェースとTarget
のインタフェースとが大きく異なっていれば多重継承で可能- 両方publicで、ということかな
実装
- 継承方式 in C++
Target
はpublic、Adaptee
はprivateで継承- 外から見たら
Target
にしか見えなくなる
- 外から見たら
- Pluggable Adapters
- 汎用モジュールは
Client
にあたる - 「汎用」にするやり方は3つ
- 汎用モジュールは
他のStructural Patternとの対比
- Bridge
- 構造が似ている
- 集約のパターンはだいたい似ると思うんですけど
- StateとStrategyとかね
- 集約のパターンはだいたい似ると思うんですけど
- 狙いは異なる
- Adapter
- 既存のクラスのインタフェースを変える
- Bridge
- インタフェースと実装とを分離する
- Adapter
- 構造が似ている
- Decorator
- インタフェースを変えずに(=透過的)機能を追加する
- 2-way adapterとは似ている
- Adapterは一般にインタフェースを変えるためのもの
- 変えた先のインタフェースに合わせるために機能追加を伴うことはある
- インタフェースを変えずに(=透過的)機能を追加する
- Proxy
- これもインタフェースを変えない
英語
- off-the-shelf
- 既製品の、ありものの
- viable
- 実行可能な