アダプターパターン
CoddyのJavaジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 71/87。
アダプターパターン(Adapter Pattern)は、互換性のないインターフェースを連携させるための構造に関するデザインパターンです。これは2つのクラス間の架け橋として機能し、あるクラスのインターフェースをクライアントが期待するインターフェースに変換します。ヨーロッパのデバイスをアメリカのコンセントに差し込めるようにする電源アダプターのようなものだと考えてください。
オーディオファイルを再生する既存の MediaPlayer インターフェースがあると想像してください。しかし、ビデオを再生するために完全に異なるインターフェースを使用するサードパーティのライブラリを統合する必要があります。
// コードが使用している既存のインターフェース
interface MediaPlayer {
void play(String filename);
}
// 互換性のないインターフェースを持つサードパーティ製クラス
class AdvancedVideoPlayer {
public void playVideo(String filename) {
System.out.println("Playing video: " + filename);
}
}アダプターは互換性のないクラスをラップし、期待されるインターフェースを実装して、それらの間の呼び出しを変換します:
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"); // 出力: ビデオを再生中: movie.mp4アダプターパターンは、ソースコードを修正することなくレガシーコードやサードパーティライブラリを統合する際に非常に有用です。クライアントは、アダプトされたクラスを操作していることを意識することなく、単に既知のインターフェースを使用します。
チャレンジ
簡単アダプターパターン(Adapter Pattern)を使用して、温度変換システムを構築しましょう!既存の気象アプリケーションは摂氏(Celsius)で動作しますが、華氏(Fahrenheit)でしか値を出力できないレガシーな温度センサーを統合する必要があります。どちらのシステムも変更することなく、そのギャップを埋めるアダプターを作成します。
コードは4つのファイルに分けて構成します:
TemperatureProvider.java: 気象アプリケーションが期待するインターフェースを定義します。摂氏の温度を double 型で返すgetTemperatureCelsius()メソッドを宣言してください。FahrenheitSensor.java: 互換性のないインターフェースを持つレガシーセンサーを表します。華氏の温度を保持する private な double 型のフィールドを持ち、コンストラクタを通じて設定されるクラスを作成してください。保持している華氏の値を返すreadFahrenheit()メソッドを持たせる必要があります。SensorAdapter.java: 華氏センサーを気象アプリケーションと互換性を持たせるためのアダプターを作成します。このアダプターはTemperatureProviderを実装し、FahrenheitSensorをラップ(保持)する必要があります。getTemperatureCelsius()が呼び出されたとき、センサーから値を読み取り、次の公式を使用して摂氏に変換して返します:(fahrenheit - 32) * 5 / 9。Main.java: すべてを統合します!1つの入力として、華氏の温度(double)を受け取ります。入力値を使用して
FahrenheitSensorを作成します。次に、このセンサーをラップするSensorAdapterを作成します。気象アプリケーションが期待されるインターフェースを通じてそれを使用できることを示すために、アダプターをTemperatureProvider型の変数に格納してください。結果を次の形式で出力してください:
Temperature: [celsius] C(celsius は小数点第1位までフォーマットします)。
入力として、華氏の温度(double)を1つ受け取ります。
例えば、入力が 98.6 の場合、出力は次のようになります:
Temperature: 37.0 CMain クラスが完全に TemperatureProvider インターフェースを通じて動作していることに注目してください。実際の温度が、舞台裏で適応された華氏センサーから来ていることを Main クラスは知りません。これがアダプターパターンの優雅さです!
自分で試してみよう
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: 摂氏(Celsius)で温度を取得し、それを表示する
// 形式: 小数点以下1桁で "Temperature: [celsius] C"
// ヒント: フォーマットには String.format("%.1f", value) を使用する
}
}
このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。
オブジェクト指向プログラミングのすべてのレッスン
4継承
継承の基本 (extends)super キーワードメソッドのオーバーライド (@Override)コンストラクタチェーンObject クラス単一継承と多段階継承なぜ多重継承ができないのかまとめ:従業員の階層構造