アダプターパターン
CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部。レッスン 71/87。
Adapter パターンは、incompatible なインターフェースを連携させる構造設計パターンです。2つのクラスの間の橋渡しとして機能し、一方のクラスのインターフェースを、クライアントが期待するインターフェースに変換します。ヨーロッパの機器をアメリカのコンセントに接続できる電源アダプターのようなものだと考えてください。
既存のMediaPlayerインターフェースがオーディオファイルを再生するとします。しかし、動画を再生するためにまったく異なるインターフェースを使用するサードパーティ製ライブラリを統合する必要があります。
// コードが使用する既存のインターフェース
interface MediaPlayer {
void play(String filename);
}
// 互換性のないインターフェースを持つサードパーティクラス
class AdvancedVideoPlayer {
public void playVideo(String filename) {
System.out.println("Playing video: " + filename);
}
}adapter は incompatible class をラップし、implements する expected interface を介して、それらの間の呼び出しを変換します。
class VideoPlayerAdapter implements MediaPlayer {
private AdvancedVideoPlayer videoPlayer;
public VideoPlayerAdapter() {
this.videoPlayer = new AdvancedVideoPlayer();
}
public void play(String filename) {
videoPlayer.playVideo(filename);
}
}これでクライアントコードは、使い慣れた MediaPlayer インターフェースを通じてビデオプレーヤーを使用できます。
MediaPlayer player = new VideoPlayerAdapter();
player.play("movie.mp4"); // 出力: Playing video: movie.mp4Adapter Patternは、レガシーコードやサードパーティライブラリを、そのソースコードを変更せずに統合する際に非常に役立ちます。クライアントは、適応されたクラスと連携していることを意識しません。単に、認識しているインターフェースを使用します。
チャレンジ
簡単Adapterパターンを使って温度変換システムを構築しましょう!Celsius温度で動作する既存の天気アプリケーションがありますが、Fahrenheitで測定値のみを出力するLegacy温度センサーを統合する必要があります。どちらのシステムも変更する代わりに、両者のギャップを橋渡しするadapterを作成します。
コードを4つのファイルに分けて整理します。
TemperatureProvider.java: 天気アプリケーションがexpectsするinterfaceをDefineします。Celsiusでの温度を表すdoubleを返すメソッドgetTemperatureCelsius()をDeclareする必要があります。FahrenheitSensor.java: これはincompatibleなinterfaceを持つlegacyセンサーを表します。Fahrenheitでの温度用のprivateなdouble fieldを持つclassをCreateし、constructorを通じて設定します。保存されたFahrenheit値を返すメソッドreadFahrenheit()を持たせます。SensorAdapter.java: Fahrenheitセンサーを天気アプリケーションとcompatibleにするadapterをCreateします。adapterはTemperatureProviderをimplementsし、FahrenheitSensorをラップする必要があります。getTemperatureCelsius()が呼び出されたら、センサーから読み取り、次の公式を使って値をCelsiusにconvertします:(fahrenheit - 32) * 5 / 9。Main.java: すべてをまとめます!1つのinput、つまりFahrenheitでの温度測定値(double)を受け取ります。input値を使って
FahrenheitSensorをCreateします。次に、このセンサーをラップするSensorAdapterをCreateします。天気アプリケーションが期待されるinterfaceを通じて利用できることを示すため、adapterをTemperatureProvider変数に保存します。結果を次の形式で出力します:
Temperature: [celsius] C。celsiusは小数点以下1桁にformatします。
1つのinput、つまりFahrenheit温度(double)を受け取ります。
たとえば、inputが98.6の場合、出力は次のようになります。
Temperature: 37.0 Cここで、Main classが完全にTemperatureProvider interfaceと連携して動作していることに注目してください。実際の温度が、背後でadapterによって変換されたFahrenheitセンサーから来ていることをまったく認識していません。これがAdapterパターンの洗練された点です。
自分で試してみよう
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
double fahrenheit = scanner.nextDouble();
// TODO: 入力値でFahrenheitSensorを作成する
// TODO: センサーをラップするSensorAdapterを作成する
// TODO: アダプターをTemperatureProvider変数に格納する
// TODO: 摂氏で温度を取得して出力する
// 形式: "Temperature: [celsius] C" で小数点以下1桁
// ヒント: フォーマットにはString.format("%.1f", value)を使用する
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造自分で練習してみよう: Javaオンラインコンパイラ