Menu
Coddy logo textTech

アダプターパターン

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.mp4

Adapter Patternは、レガシーコードやサードパーティライブラリを、そのソースコードを変更せずに統合する際に非常に役立ちます。クライアントは、適応されたクラスと連携していることを意識しません。単に、認識しているインターフェースを使用します。

challenge icon

チャレンジ

簡単

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)を使用する
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン

自分で練習してみよう: Javaオンラインコンパイラ