ソフトウェアエンジニアリングにおいて、アダプタパターンは、既存のクラスのインターフェースを別のインターフェースとして使用できるようにするソフトウェア設計パターンです(ラッパーとも呼ばれ、デコレータパターンと共通の別の名称です)。[1]:244 これは、ソースコードを変更せずに既存のクラスを他のクラスと連携させるためによく使用されます。
例えば、XML文書のドキュメントオブジェクトモデルのインターフェースを、表示可能なツリー構造に変換するアダプタなどが挙げられます。
アダプタ[ 2 ]デザインパターンは、柔軟で再利用可能なオブジェクト指向ソフトウェア、つまり実装、変更、テスト、再利用が容易なオブジェクトを設計するために、繰り返し発生する設計上の問題を解決する方法を記述した、23の有名なGang of Fourデザインパターンの1つです。
アダプタ設計パターンは次のような問題を解決します。[ 3 ]
既存のクラスが再利用できない理由は、多くの場合、そのインターフェースがクライアントが要求するインターフェースに準拠していないためです。
アダプタ設計パターンは、このような問題を解決する方法を説明しています。
adapterクラス(adaptee)の(互換性のない)インターフェースを、クライアントが必要とする別のインターフェース()に変換する別のクラスを定義しますtarget。adapter必要なインターフェースを持たないクラスを操作(再利用)するための手順を踏みます。このパターンの重要な考え方は、adapter既存のクラスを変更することなく、そのインターフェースを適応させる別の処理を実行することです。
targetクライアントは、クラスを直接操作しているのか、インターフェースadapterを持たないクラスを介して操作しているのかを知りませんtarget。
下記のUMLクラス図も参照してください。
アダプタは、互換性のない2つのインターフェースを連携させることを可能にします。これがアダプタの実際の定義です。インターフェースは互換性がない場合でも、内部機能はニーズに合致している必要があります。アダプタ設計パターンは、一方のクラスのインターフェースをクライアントが期待するインターフェースに変換することで、本来互換性のないクラス同士を連携させることを可能にします。
アダプタは、ラッパーが特定のインターフェースを尊重し、かつポリモーフィックな動作をサポートする必要がある場合に使用できます。あるいは、デコレータパターンを使用すると、実行時にインターフェースの動作を追加または変更することが可能になり、ファサードパターンは、基となるオブジェクトへのより簡単またはシンプルなインターフェースが必要な場合に使用されます。[ 1 ]: 243、252、258、260

上記のUMLクラス図では、インターフェースclientを必要とするクラスは、そのインターフェースがインターフェースに準拠していないため、クラスを直接target再利用することはできません。代わりに、インターフェースを実装するクラスを介して動作します。adapteetargetclientadaptertargetadaptee
object adapter方法は、実行時にオブジェクトtargetに委譲することでインターフェースを実装します( )。adapteeadaptee.specificOperation()class adapterを実装する方法()。targetadapteespecificOperation()このアダプタパターンでは、アダプタはラップするクラスのインスタンスを保持します。この場合、アダプタはラップされたオブジェクトのインスタンスに対して呼び出しを行います。


このアダプタパターンは、期待されるインターフェースと既存のインターフェースの両方を実装または継承する複数のポリモーフィックインターフェースを使用します。期待されるインターフェースは、特にJava (JDK 1.8以前)のようにクラスの多重継承をサポートしていない言語では、純粋なインターフェースクラスとして作成されるのが一般的です。[ 1 ]: 244


何らかのデータを提供する必要がある。例えば、あるデータがあるとしよう。コンパイル時の解決策は次のとおりである。classAclassBString
クラスB 。setStringData ( classA . getStringData ());しかし、文字列データのフォーマットを変更する必要がある場合を考えてみましょう。コンパイル時の解決策としては、継承を利用する方法があります。
public class Format1ClassA extends ClassA { @Override public String getStringData () { return format ( toString ()); } }そして、ファクトリーパターンを用いて実行時に正しく「フォーマットされた」オブジェクトを作成することもできるでしょう。
「アダプター」を用いた解決策は、以下の手順で進められます。
ClassAこの例では)をラップし、適切な形式でデータを出力します。 interface StringProvider { public String getStringData (); }パブリッククラスClassAFormat1はStringProviderを実装します{プライベートクラスAクラスA = null ;public ClassAFormat1 ( final ClassA a ) { classA = a ; }public String getStringData () { return format ( classA.getStringData ( ) ); }private String format ( final String sourceValue ) { // ソース文字列を、ソースオブジェクトのデータを必要とするオブジェクトが必要とする形式に操作するreturn sourceValue . trim (); } }public class ClassAFormat1Adapter extends Adapter { public Object adapt ( final Object anObject ) { return new ClassAFormat1 (( ClassA ) anObject ); } }adapterグローバルレジストリに登録することで、adapter実行時に検索できるようになります。 AdapterFactory.getInstance ( ) . registerAdapter ( ClassA.class , ClassAFormat1Adapter.class , " format1 " ) ;ClassAコード内で、からへデータを転送したい場合はClassB、次のように記述します。 Adapter adapter = AdapterFactory.getInstance ( ) . getAdapterFromTo ( ClassA.class , StringProvider.class , " format1 " ) ; StringProvider provider = ( StringProvider ) adapter.adapt ( classA ) ; String string = provider.getStringData ( ) ; classB.setStringData ( string ) ;あるいはもっと簡潔に言うと:
classB.setStringData ( ( ( StringProvider ) AdapterFactory.getInstance ( ) . getAdapterFromTo ( ClassA.class , StringProvider.class , " format1 " ) . adapt ( classA ) ) . getStringData ( ) ) ;Adapter adapter = AdapterFactory.getInstance ( ) . getAdapterFromTo ( ClassA.class , StringProvider.class , " format2 " ) ;ClassA、次のようになります。 ClassCAdapter adapter = AdapterFactory.getInstance ( ) . getAdapterFromTo ( ClassA.class , ImageProvider.class , " format2 " ) ; ImageProvider provider = ( ImageProvider ) adapter.adapt ( classA ) ; classC.setImage ( provider.getImage ( ) ) ;ClassB。ClassC一般ClassA的に、既存のオブジェクト階層に後付け可能な、オブジェクト間の任意のデータフローを実現するメカニズムを提供します。アダプタパターンを実装する際、分かりやすくするために、プロバイダの実装にクラス名を適用することができます。例えば、 のようにです。 には、アダプティークラスの変数をパラメータとして受け取るコンストラクタメソッドが必要です。このパラメータは、 のインスタンスメンバーに渡されます。 clientMethod が呼び出されると、アダプティーインスタンスにアクセスでき、アダプティーの必要なデータにアクセスして、そのデータに対して操作を実行し、目的の出力を生成できます。[ClassName]To[Interface]AdapterDAOToProviderAdapter[ClassName]To[Interface]Adapter
パッケージorg.wikipedia.examples ;interface ILightningPhone { void recharge (); void useLightning (); }interface IMicroUsbPhone { void recharge (); void useMicroUsb (); }class Iphone implements ILightningPhone { private boolean connector ;@Override public void useLightning () { connector = true ; System.out.println ( " Lightningが接続されました" ) ; }@Override public void recharge ( ) { if ( connector ) { System.out.println ( "充電開始" ) ; System.out.println ( "充電完了" ) ; } else { System.out.println ( "まずLightningコネクタを接続してください" ) ; } } }class Android implements IMicroUsbPhone { private boolean connector ;@Override public void useMicroUsb ( ) { connector = true ; System.out.println ( "MicroUsbが接続されました" ) ; }@Override public void recharge () { if ( connector ) { System . out . println ( "充電開始" ); System . out . println ( "充電完了" ); } else { System . out . println ( "まず MicroUsb を接続してください" ); } } } /* ソース オブジェクトをラップしながらターゲット インターフェイスを公開します */ class LightningToMicroUsbAdapter implements IMicroUsbPhone { private final ILightningPhone lightningPhone ;public LightningToMicroUsbAdapter ( ILightningPhone lightningPhone ) { this.lightningPhone = lightningPhone ; }@Override public void useMicroUsb ( ) { System.out.println ( " MicroUsb接続済み" ) ; lightningPhone.useLightning ( ) ; }@Override public void recharge () { lightningPhone.recharge ( ) ; } }public class AdapterDemo { static void rechargeMicroUsbPhone ( IMicroUsbPhone phone ) { phone . useMicroUsb (); phone . recharge (); }static void rechargeLightningPhone ( ILightningPhone phone ) { phone.useLightning ( ) ; phone.recharge ( ) ; }public static void main ( String [] args ) { Android android = new Android (); Iphone iPhone = new Iphone ();System.out.println ( " MicroUsbでAndroidを充電中" ) ; rechargeMicroUsbPhone ( android ) ;System.out.println ( "LightningでiPhoneを充電しています" ) ; rechargeLightningPhone ( iPhone ) ;System.out.println ( "iPhoneをMicroUSBで充電しています" ) ; rechargeMicroUsbPhone ( new LightningToMicroUsbAdapter ( iPhone ) ) ; } }出力
MicroUSBでAndroid端末を充電する MicroUSB接続済み 充電を開始しました 充電完了 LightningケーブルでiPhoneを充電する Lightning接続 充電を開始しました 充電完了 MicroUSBでiPhoneを充電する MicroUSB接続済み Lightning接続 充電を開始しました 充電完了
"""アダプターパターンの例。""" from abc import ABCMeta , abstractmethod from typing import NoReturnRECHARGE : list [ str ] = [ "充電を開始しました。" , "充電が完了しました。" ] POWER_ADAPTERS : dict [ str , str ] = { "Android" : "MicroUSB" , "iPhone" : "Lightning" } CONNECTED_MSG : str = " {}が接続されました。" CONNECT_FIRST_MSG : str = " {} を最初に接続してください。"class RechargeTemplate ( metaclass = ABCMeta ): @abstractmethod def recharge ( self ) -> NoReturn : raise NotImplementedError ( "これを実装する必要があります。" )class FormatIPhone ( RechargeTemplate ): @abstractmethod def use_lightning ( self ) -> NoReturn : raise NotImplementedError ( "You should implement this." )class FormatAndroid ( RechargeTemplate ): @abstractmethod def use_micro_usb ( self ) -> NoReturn : raise NotImplementedError ( "You should implement this." )class IPhone ( FormatIPhone ): __name__ : str = "iPhone"def __init __ ( self ) : self.connector : bool = Falsedef use_lightning ( self ) - > None : self.connector = True print ( CONNECTED_MSG.format ( POWER_ADAPTERS [ self .__ name__ ] ) )def recharge ( self ) - > None : if self.connector : for state in RECHARGE : print ( state ) else : print ( CONNECT_FIRST_MSG.format ( POWER_ADAPTERS [ self .__ name__ ] ) )class Android ( FormatAndroid ): __name__ : str = "Android"def __init __ ( self ) - > None : self.connector : bool = Falsedef use_micro_usb ( self ) - > None : self.connector = True print ( CONNECTED_MSG.format ( POWER_ADAPTERS [ self .__ name__ ] ) )def recharge ( self ) - > None : if self.connector : for state in RECHARGE : print ( state ) else : print ( CONNECT_FIRST_MSG.format ( POWER_ADAPTERS [ self .__ name__ ] ) )class IPhoneAdapter ( FormatAndroid ): def __init__ ( self , mobile : FormatAndroid ) -> None : self . mobile : FormatAndroid = mobiledef recharge ( self ) - > None : self.mobile.recharge ( )def use_micro_usb ( self ) - > None : print ( CONNECTED_MSG.format ( POWER_ADAPTERS [ " Android " ] ) ) self.mobile.use_lightning ( )class AndroidRecharger : def __init__ ( self ) -> None : self . phone : Android = Android () self . phone . use_micro_usb () self . phone . recharge ()class IPhoneMicroUSBRecharger : def __init__ ( self ) -> None : self . phone : IPhone = IPhone () self . phone_adapter : IPhoneAdapter = IPhoneAdapter ( self . phone ) self . phone_adapter . use_micro_usb () self . phone_adapter . recharge ()class IPhoneRecharger : def __init__ ( self ) -> None : self . phone : IPhone = IPhone () self . phone . use_lightning () self . phone . recharge ()print ( "MicroUSB充電器でAndroidを充電しています。" ) AndroidRecharger () print ()print ( "アダプターパターンを使用してMicroUSBでiPhoneを充電しています。" ) IPhoneMicroUSBRecharger () print ()print ( "iPhone充電器でiPhoneを充電しています。" ) iPhoneRecharger ()名前空間Wikipedia.Examples ;Systemを使用します。interface ILightningPhone { void ConnectLightning (); void Recharge (); }interface IUsbPhone { void ConnectUsb (); void Recharge (); }sealed class AndroidPhone : IUsbPhone { private bool isConnected ;public void ConnectUsb ( ) { this.isConnected = true ; Console.WriteLine ( "Androidスマートフォンが接続されました。" ) ; }public void Recharge () { if ( this.isConnected ) { Console.WriteLine ( "Androidスマートフォンを充電しています。" ) ; } else { Console.WriteLine ( "まずUSBケーブルを接続してください。" ) ; } } }sealed class ApplePhone : ILightningPhone { private bool isConnected ;public void ConnectLightning () { this.isConnected = true ; Console.WriteLine ( " Appleの電話が接続されました。" ) ; }public void Recharge () { if ( this.isConnected ) { Console.WriteLine ( "Apple製スマートフォンを充電中です。" ) ; } else { Console.WriteLine ( "まずLightningケーブルを接続してください。" ) ; } } }sealed class LightningToUsbAdapter : IUsbPhone { private readonly ILightningPhone lightningPhone ;private bool isConnected ;public LightningToUsbAdapter ( ILightningPhone lightningPhone ) { this.lightningPhone = lightningPhone ; }public void ConnectUsb ( ) { this.lightningPhone.ConnectLightning ( ) ; }public void Recharge ( ) { this.lightningPhone.Recharge ( ) ; } }public class AdapterDemo { static void Main ( string [] args ) { ILightningPhone applePhone = new ApplePhone (); IUsbPhone adapterCable = new LightningToUsbAdapter ( applePhone ); adapterCable . ConnectUsb (); adapterCable . Recharge (); } }出力:
Apple製スマートフォンが接続されました。Apple製スマートフォンを充電中です。