Adapterパターン
目的
修正することのできない既存オブジェクトを、特定のインターフェースに適合させる。 既存のクラスを修正することなく、適切なインターフェース(メソッド)を追加することができる。問題
使用したいデータや振る舞いが既存システム内に存在しているものの、そのインターフェースが正しくない場合。解決策
必要なインターフェースを保持したラッパーをAdapterによって提供する。
問題例
<?php class MyNameViewer { public function viewName(MyPersonB $person): void { echo $person->getName(); } }
<?php class MyPersonB { /** * @var string */ private $name; /** * MyPersonB constructor. * @param string $name */ public function __construct(string $name) { $this->name = $name; } /** * @return string */ public function getName(): string { return $this->name; } }
以上のような既存のプログラムがあり、 viewName(MyPersonB $person)はMyPersonBクラスの型が指定されている。
<?php $viewer = new App\MyNameViewer(); $viewer->viewName(new App\MyPersonB("John"));
John
と表示される。
<?php class MyPersonA { /** * @var string */ private $firstName; /** * @var string */ private $lastName; /** * MyPersonA constructor. * @param string $firstName * @param string $lastName */ public function __construct(string $firstName, string $lastName) { $this->firstName = $firstName; $this->lastName = $lastName; } /** * @return string */ public function getFirstName(): string { return $this->firstName; } /** * @return string */ public function getLastName(): string { return $this->lastName; } }
このMyPersonAオブジェクトをMyNameViewerに渡して表示したいときにどうするか。
Fatal error: Uncaught TypeError: Argument 1 passed to App\MyNameViewer::viewName() must be an instance of App\MyPersonB, instance of App\MyPersonA given
当然MyPersonAを入れてもエラーになる。
こういうときにAdapterパターンを使う。
<?php class Adapter extends MyPersonB { /** * @var MyPersonA */ private $person; /** * Adapter constructor. * @param MyPersonA $person */ public function __construct(MyPersonA $person) { $this->person = $person; } public function getName(): string { return $this->person->getFirstName() . $this->person->getLastName(); } }
MyPersonBをかぶせたAdapterを作成する。
<?php $adapter = new Other\Adapter(new \Other\MyPersonA("Ken", "Thompson")); $viewer = new Other\MyNameViewer(); $viewer->viewName($adapter);
アダプティクラス(MyPersonBクラス)の仕様を修正することなく、別のインターフェースへの拡張を容易にする。 元々、MyPersonBクラスがFirstNameとLastNameを両方表示していれば問題なかった。このレベルならMyPersonBに追加したほうが早い。 インターフェースを使用したパターン。
<?php interface IMyPerson { public function getName(): string; }
<?php class MyPersonA { /** * @var string */ private $firstName; /** * @var string */ private $lastName; /** * MyPersonA constructor. * @param string $firstName * @param string $lastName */ public function __construct(string $firstName, string $lastName) { $this->firstName = $firstName; $this->lastName = $lastName; } /** * @return string */ public function getFirstName(): string { return $this->firstName; } /** * @return string */ public function getLastName(): string { return $this->lastName; } public function getName(): string { return $this->getFirstName() . $this->getLastName(); } }
<?php class MyPersonB implements IMyPerson { /** * @var string */ private $name; /** * MyPersonB constructor. * @param string $name */ public function __construct(string $name) { $this->name = $name; } /** * @return string */ public function getName(): string { return $this->name; } }
<?php class Adapter implements IMyPerson { /** * @var MyPersonA */ private $person; /** * Adapter constructor. * @param MyPersonA $person */ public function __construct(MyPersonA $person) { $this->person = $person; } public function getName(): string { return $this->person->getName(); } }
<?php class MyNameViewer { /** * @param IMyPerson $person */ public function viewName(IMyPerson $person): void { echo $person->getName(); } }
<?php $adapter = new Other\Adapter(new \Other\MyPersonA("Ken", "Thompson")); $viewer = new Other\MyNameViewer(); $viewer->viewName($adapter);
- 参考
オブジェクト指向のこころ (SOFTWARE PATTERNS SERIES)
- 作者: アラン・シャロウェイ,ジェームズ・R・トロット,村上雅章
- 出版社/メーカー: 丸善出版
- 発売日: 2014/03/11
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (6件) を見る
- 作者: 結城浩
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2004/06/19
- メディア: 大型本
- 購入: 51人 クリック: 762回
- この商品を含むブログ (397件) を見る
PHPによるデザインパターン入門 - Adapter〜APIを変更する - Do You PHP はてなJavaデザインパターン徹底攻略 (標準プログラマーズライブラリ)
- 作者: 日立ソフトウェアエンジニアリングインターネットビジネス部
- 出版社/メーカー: 技術評論社
- 発売日: 2002/09
- メディア: 単行本
- 購入: 7人 クリック: 33回
- この商品を含むブログ (24件) を見る