Adapterパターン
CoddyのPHPジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 76/91。
アダプターパターンは、互換性のないinterfaceを持つオブジェクト同士が連携できるようにする構造設計パターンです。2つのinterfaceの間の橋渡しとして機能し、一方の形式の呼び出しを別の形式に変換します。
支払いを処理するapplicationを構築していて、サードパーティの支払いlibraryを統合する必要があると想像してください。そのlibraryは完全に動作しますが、そのinterfaceはコードがexpectsものと一致しません。application全体を書き直す代わりに、2つの間を翻訳するadapterを作成します。
<?php
// アプリケーションが期待するインターフェース
interface PaymentProcessor {
public function pay(float $amount): string;
}
// 異なるインターフェースを持つサードパーティライブラリ
class StripeAPI {
public function createCharge(int $cents, string $currency): string {
return "Charged {$cents} {$currency} via Stripe";
}
}
adapter は、内部ではサードパーティのクラスを使用しながら、期待されるインターフェースを実装します。
<?php
class StripeAdapter implements PaymentProcessor {
public function __construct(private StripeAPI $stripe) {}
public function pay(float $amount): string {
$cents = (int)($amount * 100);
return $this->stripe->createCharge($cents, 'USD');
}
}
$stripe = new StripeAPI();
$processor = new StripeAdapter($stripe);
echo $processor->pay(29.99);
Output:
Charged 2999 USD via Stripeadapter はドルを cents に converts し、適切な method を呼び出します。あなたの application code は PaymentProcessor についてしか知らず、Stripe 固有の要件にはまったく関与しません。後で different な決済プロバイダーに切り替える場合も、既存のコードを変更せずに新しい adapter を作成するだけです。
チャレンジ
簡単Adapter Pattern を使用して温度変換システムを構築しましょう。Fahrenheit で測定値を出力する古い温度センサーがありますが、最新の気象アプリケーションではすべての温度を Celsius で受け取ることを expects しています。どちらのシステムも変更する代わりに、両者の隔たりを埋める adapter を作成します。
コードを4つのファイルに分けて整理します。
TemperatureSensor.php: 気象アプリケーションが expects するTemperatureSensorinterface を Define します。温度を Celsius で返すgetTemperature(): floatmethod を have する必要があります。LegacySensor.php: 古い hardware をシミュレートするLegacySensorclass を Create します。この class は、application が必要とするものとは different な interface を have します。- constructor で Fahrenheit の測定値を受け取ります(constructor promotion を使用します)
- 保存された Fahrenheit の値を返す
readFahrenheit(): floatmethod を have します
LegacySensorAdapter.php: TemperatureSensor interface と LegacySensor class の両方を Include します。TemperatureSensorを implements し、LegacySensorをラップするLegacySensorAdapterclass を Create します。adapter は次のようにします。- constructor で
LegacySensorを Accept します - legacy sensor から Fahrenheit の値を読み取り、formula
(fahrenheit - 32) * 5 / 9を使用して Celsius に変換することで、getTemperature()を Implement します
- constructor で
main.php: LegacySensorAdapter file を Include します。入力として Fahrenheit の温度を1つ受け取ります。入力温度を使って
LegacySensorを Create し、それをLegacySensorAdapterでラップします。adapter でgetTemperature()を Call し、結果を小数点以下2桁に丸めて Output します。Output format は次のとおりです:
Temperature: [celsius]C
この challenge は、Adapter Pattern によって既存の code を変更せずに互換性のない interface を統合できることを示します。気象アプリケーションは TemperatureSensor interface のみを使用し、実際の測定値が legacy の Fahrenheit sensor から取得されていることを完全に意識しません。
自分で試してみよう
<?php
require_once 'LegacySensorAdapter.php';
// 入力を読み取る
$fahrenheit = floatval(trim(fgets(STDIN)));
// TODO: 入力温度でLegacySensorを作成する
// TODO: それをLegacySensorAdapterでラップする
// TODO: アダプターでgetTemperature()を呼び出す
// TODO: 結果を小数点以下2桁に丸めて出力する
// 出力形式: Temperature: [celsius]C
?>このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
1OOPの基礎
外部ファイルOOP入門クラスとオブジェクトの違い$thisキーワードメソッドプロパティコンストラクター(__construct)デストラクター(__destruct)復習 - 簡単な電卓13デザインパターン パート2
CommandパターンAdapterパターンDecoratorパターンTemplate MethodパターンStateパターンCompositeパターンRepositoryパターン自分で練習してみよう: PHPオンラインコンパイラ