アダプターパターン

アダプターパターン(Adapter Pattern)は、互換性のない2つのインターフェース間の橋渡し役を担う構造型デザインパターンです。仲介役(アダプター)を通じて、あるクラスのインターフェースをクライアントが期待する別のインターフェースに変換し、元々一緒に動作できなかったクラスが連携して動作できるようにします。

このパターンは単一のクラスを含み、そのクラスは独立した、または互換性のないインターフェース機能を追加する役割を担います。実際の例を挙げると、カードリーダーはメモリーカードとノートパソコンの間のアダプターとして機能します。メモリーカードをカードリーダーに挿入し、カードリーダーをノートパソコンに挿入することで、ノートパソコンを通じてメモリーカードを読み取ることができます。

MP3ファイルしか再生できないオーディオプレーヤーがあるとします。VLCファイルとMP4ファイルを再生する必要がある場合、アダプターを作成することで実現できます:

  • ターゲットインターフェース:複数の形式のファイルを再生できるオーディオプレーヤーインターフェースを定義します。
  • アダプティクラス:既存のオーディオプレーヤーであり、MP3ファイルのみ再生できます。
  • アダプタークラス:新しいクラスを作成し、ターゲットインターフェースを実装して、内部でアダプティクラスを使用してMP3ファイルを再生し、同時にVLCおよびMP4ファイルのサポートを追加します。

概要

アダプターパターンは、異なるインターフェース間の互換性の問題を解決することを目的としたソフトウェアデザインパターンです。

目的:あるクラスのインターフェースを別のインターフェースに変換し、元々互換性のないクラスが連携して動作できるようにします。

主に解決する問題:ソフトウェアシステムにおいて、既存のオブジェクトを新しい環境に配置する必要があるが、新しい環境が要求するインターフェースが既存のオブジェクトと一致しない場合。

使用シーン

  • 既存のクラスを使用する必要があるが、そのインターフェースがシステムの要件を満たしていない場合。
  • 再利用可能なクラスを作成し、複数の無関係なクラス(将来導入される可能性のあるクラスを含む)と連携させたい場合。これらのクラスには統一されたインターフェースがない可能性があります。
  • インターフェース変換を通じて、あるクラスを別のクラス体系に統合します。

実装方法

  • 継承または依存:柔軟性を保つために、継承ではなく依存関係を使用することを推奨します。

主要コード

アダプターは既存のオブジェクトを継承または依存し、必要なターゲットインターフェースを実装します。

応用例

  • 電圧アダプター:110Vを220Vに変換して、さまざまな国の電気製品の規格に適合させます。
  • インターフェース変換:例えば、Java JDK 1.1 の Enumeration インターフェースを 1.2 の Iterator インターフェースに変換します。
  • クロスプラットフォーム実行:Linux上でWindowsプログラムを実行します。
  • データベース接続:JavaのJDBCは、アダプターパターンを通じてさまざまなタイプのデータベースと連携します。

利点

  • 直接的な関連のないクラス間の連携を促進します。
  • クラスの再利用性を高めます。
  • クラスの透過性を高めます。
  • 優れた柔軟性を提供します。

欠点

  • アダプターを過度に使用すると、システム構造が混乱し、理解や保守が困難になる可能性があります。
  • Javaでは、継承できるクラスが1つだけであるため、適合できるクラスも1つだけであり、ターゲットクラスは抽象クラスでなければなりません。

使用上のアドバイス

  • アダプターパターンは慎重に使用する必要があります。特に詳細設計段階では、既存システムの問題を解決するために主に使用されます。
  • 正常に動作しているシステムのインターフェースを変更することを検討している場合、アダプターパターンは適切な選択です。

このようにして、アダプターパターンは中核となる概念と応用を明確に表現でき、不必要な複雑さを回避できます。

構造

アダプターパターンには、以下の主要な役割が含まれます:

  • ターゲットインターフェース(Target):クライアントが必要とするインターフェースを定義します。
  • アダプティクラス(Adaptee):適合が必要な既存のインターフェースを定義します。
  • アダプタークラス(Adapter):ターゲットインターフェースを実装し、コンポジションまたは継承の方法でアダプティクラスのメソッドを呼び出し、ターゲットインターフェースを実現します。

実装

私たちは...を持っていますMediaPlayerインターフェースと、それを実装したMediaPlayerインターフェースのエンティティクラスAudioPlayer。デフォルトでは、AudioPlayermp3形式のオーディオファイルを再生できます。

私たちはもう一つのインターフェースも持っていますAdvancedMediaPlayerと、それを実装したAdvancedMediaPlayerインターフェースのエンティティクラス。このクラスは vlc および mp4 形式のファイルを再生できます。

私たちは...にAudioPlayer他の形式のオーディオファイルを再生させたいと考えています。この機能を実現するために、...を実装したMediaPlayerインターフェースのアダプタークラスMediaAdapterを作成し、...を使用してAdvancedMediaPlayerオブジェクトで必要な形式を再生します。

AudioPlayerアダプタークラスを使用してMediaAdapter必要なオーディオタイプを渡します。必要な形式のオーディオを再生できる実際のクラスを知る必要はありません。AdapterPatternDemoクラスは...を使用してAudioPlayerクラスでさまざまな形式を再生します。

适配器模式的 UML 图

ステップ 1

メディアプレーヤーと、より高度なメディアプレーヤーのインターフェースを作成します。

MediaPlayer.java

public interface MediaPlayer { public void play(String audioType, String fileName); }

AdvancedMediaPlayer.java

public interface AdvancedMediaPlayer { public void playVlc(String fileName); public void playMp4(String fileName); }

ステップ 2

実装した...を作成しますAdvancedMediaPlayerインターフェースのエンティティクラス。

VlcPlayer.java

public class VlcPlayer implements AdvancedMediaPlayer{ @Override public void playVlc(String fileName) { System.out.println("Playing vlc file. Name: "+ fileName); } @Override public void playMp4(String fileName) { //何もしません } }

Mp4Player.java

public class Mp4Player implements AdvancedMediaPlayer{ @Override public void playVlc(String fileName) { //何もしません } @Override public void playMp4(String fileName) { System.out.println("Playing mp4 file. Name: "+ fileName); } }

ステップ 3

実装した...を作成しますMediaPlayerインターフェースのアダプタークラス。

MediaAdapter.java

public class MediaAdapter implements MediaPlayer { AdvancedMediaPlayer advancedMusicPlayer; public MediaAdapter(String audioType){ if(audioType.equalsIgnoreCase("vlc") ){ advancedMusicPlayer = new VlcPlayer(); } else if (audioType.equalsIgnoreCase("mp4")){ advancedMusicPlayer = new Mp4Player(); } } @Override public void play(String audioType, String fileName) { if(audioType.equalsIgnoreCase("vlc")){ advancedMusicPlayer.playVlc(fileName); }else if(audioType.equalsIgnoreCase("mp4")){ advancedMusicPlayer.playMp4(fileName); } } }

ステップ 4

実装した...を作成しますMediaPlayerインターフェースのエンティティクラス。

AudioPlayer.java

public class AudioPlayer implements MediaPlayer { MediaAdapter mediaAdapter; @Override public void play(String audioType, String fileName) { //mp3音楽ファイルを再生する内蔵サポート if(audioType.equalsIgnoreCase("mp3")){ System.out.println("Playing mp3 file. Name: "+ fileName); } //mediaAdapter は他のファイル形式を再生するサポートを提供します else if(audioType.equalsIgnoreCase("vlc") || audioType.equalsIgnoreCase("mp4")){ mediaAdapter = new MediaAdapter(audioType); mediaAdapter.play(audioType, fileName); } else{ System.out.println("Invalid media. "+ audioType + " format not supported"); } } }

ステップ 5

AudioPlayer を使用して、さまざまなタイプのオーディオ形式を再生します。

AdapterPatternDemo.java

public class AdapterPatternDemo { public static void main(String[] args) { AudioPlayer audioPlayer = new AudioPlayer(); audioPlayer.play("mp3", "beyond the horizon.mp3"); audioPlayer.play("mp4", "alone.mp4"); audioPlayer.play("vlc", "far far away.vlc"); audioPlayer.play("avi", "mind me.avi"); } }

ステップ 6

プログラムを実行し、結果を出力します:

Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported
その他の拡張