【オブジェクト指向のこころ】7章 Adapterパターン

デザインパターンとともに学ぶオブジェクト指向のこころ」の学習記録。
「第7章 Adapterパターン」のまとめ。


Adapterパターンは、クラス(またはクラス群)のインタフェースを、望み通りのインタフェースに変換することが可能になる。
これには望み通りのインタフェースを保持した新規クラスを生成し、既存クラスを包み込むことで、既存クラスのメソッドに対するラッパを実装することになる。

Adapterパターンの目的

GoFによるAdapterパターンの目的は以下の通り。

  • あるクラスのインタフェースを、クライアントが望むインタフェースに変換する。
  • Adapterによってクラス群は互換性のあるインタフェースを持つことになり、協調して動作できるようになる。

適用例

抽象クラスであるShapeを継承したPoint、Line、Squareがあるとする。
ここにCircleを追加することを考える。

他のクラスと同様に実装する場合、display()fill()undisplay()を実装することを考える。
実装するときに既存コードを確認すると、XXCircleという円を表現したクラスが存在することが分かった。
ただし想定していたインタフェース(メソッド名)とは異なっていた。
XXCircleをShapeに合わせてメソッド名を変更すると既存コード全てへ影響が出る。

このような場合、XXCircleには手を付けず、適合(Adapt)することを考える。

http://www.plantuml.com/plantuml/png/bL8zJyCm4DtlLtW4LGNcgegAEbNgWDIbg-iSxGb_1FiyX9B_JX8dQI82KZVVU_VUdVsy2ImzHwFXGZaAD0MNmg0veGyGFiWMqaiZb9OXl39xEaN6dNBsG5yeNW1QHcmreMLnXGf0dW9xgLWawd2H1TRC8Y3lIKacPnyUON6kIpUK3RjrsldwVEqTgaLEeT2od8BlfFKKYVRMMFKxlJbgLngPzD9vmPuitjD_-8pItwNOabUwKQnLSzVLsSiokwdNposSJUdaECz5-riyJ3iUXtd_FtvdwJ7FciOTXnJ5u3dfw2RkU9PF-_v9HZidhm2W-q9FMVTZLY86X7HUVo-NASynqEGrhbCUOoJT7pPeysZq3m00

具体的には、CircleにXXCircleを保持させる。
Circleオブジェクトに対するリクエストをXXCircleオブジェクトに転送する。

http://www.plantuml.com/plantuml/png/bL9DJyCm3BtdL-G8J0FEqpGDxLHf1wHUTarJmopoKHBdK4R_EssQG2SLGM_sUtwsvUUz9-4eQCNEM0C7tL3BDUWAd6V-3KqZdD1SAk7z4v73AX0KqfeIFu0_CXOPVb08XlY5TOo9ofCJalX8bMVHGC-iFD0HfI2qvkQMhLxxrEOqiWUhhElZI-xGhMhqZHBjDVY2IbqZmVmKTdcdPujnfKcJB9qN7D70alhoFGYtI7509zMWMElsT4hPXkTmmOt-EpBt_jk1hHnQRnpKkw6m89zcRHyYivjMvF45pVDnfr_9O6Ramyei_T7zBhtDXWSFR8otd-lrQEe4YAPDycJA54ctJMUuwv7lU-_1r46hBm00

コード例:

class Circle extends Shape {
private XXCircle myXXCircle;

    public Circle() {
        myXXCircle = new XXCircle();
    }

    @override
    public void display() {
        myXXCircle.displayIt();
    }
}

ここまでの例では、ラッパクラス(Circle)で必要な機能を既存クラス(XXCircle)が全て備えていた。
既存クラスが一部の機能を備えていなければ、ラッパクラスで実装すれば良い。

Adapterパターンの種類

Adapterパターンには2つの種類がある。

Object Adapterパターン

上述の例のように、あるオブジェクトが他のオブジェクトを保持してAdapterを実装する方法。
委譲を利用した方法。

http://www.plantuml.com/plantuml/png/bOxDgi8m48NtynHPtYjKrAM8j7RbmfM-GDeCDfYa9JC1V_JTZMrJSEdkdFFnmSc9fUTW3JHQeK3RyKrOj1Lw0hferqalhQYD92gOlQu2uxvktL7VKIm0UY9Aez6nUC0hBIVfp_XPk0y7vAPLox__hxwAVJ8A9Jj6_xk2KR4zB28SqcvAvI2C3-VRz6mj0Y6CPVFCidGW4hmoEaMGbbc2664Z2VA8WpLl

Class Adapterパターン

多重継承を使用してAdapterを実装する方法。
継承を利用した方法。
既存クラスを継承し、求めている処理が呼び出されたとき、既存クラスのメソッドへ転送する。

http://www.plantuml.com/plantuml/png/bOwzJWCn48JxVOejeSW9A564SgIYe88NSCu3iV0wbdSjyPEyE-OI8oZJM3EU-UnPgRbYLI9jWmT3idsmG3OeIleMKdR52K_HgOvc9MoguM7QfQVm2RuYcXDUnu1a_4K7ef0CvSLDu6TNNl5pQxDuX6rt_lhYyf-_QVxGtnczouq-7q53P0x75XxL_QzQ7u7Jok6kBxlbgg2JMUw7eGzeIP0S8QslrBzOxXUBFmsy6v9NMhMpIlm6

Facade vs Adapter

FacadeパターンとAdapterパターンは既存クラスを使用したいがインタフェースが期待する状態ではない場合に適用する性質の似たパターンである。
違いとしては以下の通り。

  • Facadeパターンはインタフェースを設計し直す必要がないが、Adapterパターンはインタフェースを設計し直す。
  • Facadeパターンはポリモーフィズムに則った振る舞いは不要。
  • Adapterパターンはポリモーフィズムに則った振る舞いに適用できる。(上述の例のようにShape型としての振る舞わせたい場合に適用できる。単にインタフェースを適合したい場合だけの場合もある。)

Facadeパターンは複数クラスを隠蔽、Adapterパターンは単一クラスの隠蔽、といったイメージがあるが、Facadeが複雑な単一クラスの処理を隠蔽、Adapterが複数のクラスを保持し隠蔽することもあり得る。

つまり以下のような違いがある。

  • Facadeパターンはインタフェースを簡素化する
  • Adapterパターンは既存のインタフェースを他のインタフェースに変換する