Adapterパターンとは
異なる2つのインターフェース(API)の間に入って、その差を埋めるためのデザインパターンのことをAdapterパターンと呼びます。
すでにあるものと必要なものの間に入ってその差を埋めるようなイメージです。
AクラスがBクラスを呼び出そうとする際に、何かしらの不都合があって呼び出せないとしましょう。
その際にBクラスを変更するのではなく、新しくCクラスを作成して、AクラスはCクラス経由でBクラスを呼び出そうとする仕組みです。
図にするとこんな感じですかね。
Adapterパターンで登場する概念
-
Target
必要となるメソッドを定義しています。
先ほどの例でいうところの吹き出しに当てはまります。 -
Client
呼び出し元
先ほどの例でいうところのAクラスに当てはまります。 -
Adaptee
適合される側のことで、すでに何かしらのメソッドを持っています。
先ほどの例でいうところのBクラスに当てはまります。 -
Adapter
今回のデザインパターンのメイン部分です。
clientとadapteeの間に入り、targetを満たすようにします。
先ほどの例でいうところのCクラスに当てはまります。
簡単なコードを書いてみる
Adaptee
既存のコードと仮定します。元々Bannerクラスはあったとしましょう。
class Banner
{
private $string;
public function __construct($string)
{
$this->string = $string;
}
public function showWithParen()
{
echo "(" . $this->string . ")";
}
public function showWithAster()
{
echo "*" . $this->string . "*";
}
}
Target
clientから先ほどのBannerクラスを直接呼び出せないと仮定し、adapterパターンを使ってそれを解決したいです。
解決するために必要なメソッドを考えinterfaceとして定義しておきます。
interface Output
{
public function outputWeak();
public function outputStrong();
}
Adapter
clientとadapteeの間に入り、targetを満たすようにadapterを作成します。
これにより既存のadpteeであるBannerクラスには変更を加えずに、clientから呼び出せるようになりました。
class OutputBanner extends Banner implements Output
{
public function __construct($string)
{
parent::__construct($string);
}
public function outputWeak()
{
$this->showWithParen();
}
public function outputStrong()
{
$this->showWithAster();
}
}
Client
ここでadapterであるOutputBannerクラスを呼び出します。
class Main
{
public function main()
{
$ob = new OutputBanner("hoge");
$ob->outputWeak();
$ob->outputStrong();
}
}
メリット
既存のコードを再利用しやすいということと、既存のコードに手を加えなくて済むということでしょうか。
手を加えなければテストコードを書き換える必要もありませんし、不具合があっても対象が追加したadapterの部分であるということはわかりやすいと思います。
実務で使っている場面
自分が触っているプロダクトでは、一部ソースコードのリプレイスを行いました。
そのため極力リプレイス前の古いコードは直接使用しないように、このadapterパターンを使っています。
古いコードを再利用しつつ、リプレイス後のディレクトリへコードを書き、リプレイス前のコードは直接使用しないようにしています。
参考
Java言語で学ぶデザインパターン入門
Do You PHP
TECHSCORE