コンセプト
Adapter
GOF は、クラスのインターフェイスをユーザーが必要とする別のインターフェイスに変換するという方法でアダプター パターン ( ) を定義します。アダプター パターンを使用すると、インターフェイスに互換性がないために連携できないクラスが連携できるようになります。
GOFでは、アダプタパターンはクラスアダプタパターンとオブジェクトアダプタパターンに分けられます。唯一の違いは、アダプターの役割の適応された役割への適応が、継承または合成によって実現されるかどうかです。Java では多重継承がサポートされておらず、カプセル化が壊れている疑いがあるためです。また、[複数の組み合わせと少ない継承][2]も提唱しています。そこで今回はオブジェクトアダプターを中心に紹介します。
使用
使っている電子機器の充電器のモデルが違う、という生活の常識は誰もが持っていると思います。現在主流の携帯電話充電ポートには、主に Mini USB、Micro USB、Lightning が含まれます。その中で、Mini USB はカードリーダー、MP3、デジタルカメラ、モバイルハードディスクなどに広く使われています。マイクロ USB はミニ USB よりも薄いため、Android スマートフォンでよく使われる携帯電話で広く使用されています。もう 1 つの一般的な充電ポートは、Apple の携帯電話で一般的に使用されている Lightning です。
もちろん、特定のモデルの携帯電話は、特定のモデルの充電器でのみ充電できます。たとえば、iPhone 6 は Lightning インターフェイスを備えた充電器でのみ充電できます。しかし、Android の Micro USB 充電ケーブルしか身の回りにない場合、Apple の携帯電話を充電できるでしょうか? アダプターがある限り、答えは「はい」です。
アダプターは私たちの日常生活のあらゆるところで見られます。アダプター パターンはまさに同様の問題を解決するものです。
プログラム設計プロセス中にも同様のシナリオに遭遇する可能性があります。
1. システムは既存のクラスを使用する必要がありますが、そのようなインターフェイスはシステムのニーズを満たしていません。
2. 将来導入される可能性のあるクラスなど、相互にあまり関係のないいくつかのクラスを操作するための再利用可能なクラスを作成したいのですが、これらのソース クラスは必ずしも一貫したインターフェイスを持っているわけではありません。
3. インターフェイス変換を通じて、クラスを別のクラス システムに挿入します。(たとえば、トラと鳥、現在はフライング タイガーが存在します。エンティティの要件を増やすことなく、タイガー オブジェクトを含むアダプターを追加して、フライング インターフェースを実現します。)
上記のシナリオは、アダプター パターンの使用に適しています。
実現方法
アダプター パターンには次の役割が含まれます。
ターゲット: ターゲット抽象クラス
アダプター: アダプタークラス
アダプティ: アダプタクラス
クライアント: クライアントクラス
ここでは、記事の冒頭で紹介した携帯電話の充電ポートの例を使用し、Android 充電器を使用して Apple デバイスを充電する機能を持つアダプターを定義します。
まずインターフェイスを定義します。
/**
* MicroUsb充电器接口
*/
public interface MicroUsbInterface {
public void chargeWithMicroUsb();
}
/**
* Lightning充电器接口
*/
public interface LightningInterface {
public void chargeWithLightning();
}
具体的な実装クラスを定義する
/**
* 安卓设备的充电器
*/
public class AndroidCharger implements MicroUsbInterface {
@Override
public void chargeWithMicroUsb() {
System.out.println("使用MicroUsb型号的充电器充电...");
}
}
/**
* 苹果设备的充电器
*/
public class AppleCharger implements LightningInterface {
@Override
public void chargeWithLightning() {
System.out.println("使用Lightning型号的充电器充电...");
}
}
アダプタ モードを使用して MicroUsb を Lightning に変換したいため、ここで AppleCharger を定義する必要はありません。アダプターを使用する目的は、新しいアダプターを交換することであるためです。例をより完全にするためにここで定義されています。
2 台の電話を定義する
public class Iphone6Plus {
private LightningInterface lightningInterface;
public Iphone6Plus() {
}
public Iphone6Plus(LightningInterface lightningInterface) {
this.lightningInterface = lightningInterface;
}
public void charge() {
System.out.println("开始给我的Iphone6Plus手机充电...");
lightningInterface.chargeWithLightning();
System.out.println("结束给我的Iphone6Plus手机充电...");
}
public LightningInterface getLightningInterface() {
return lightningInterface;
}
public void setLightningInterface(LightningInterface lightningInterface) {
this.lightningInterface = lightningInterface;
}
}
public class GalaxyS7 {
private MicroUsbInterface microUsbInterface;
public GalaxyS7() {
}
public GalaxyS7(MicroUsbInterface microUsbInterface) {
this.microUsbInterface = microUsbInterface;
}
public void charge(){
System.out.println("开始给我的GalaxyS7手机充电...");
microUsbInterface.chargeWithMicroUsb();
System.out.println("结束给我的GalaxyS7手机充电...");
}
public MicroUsbInterface getMicroUsbInterface() {
return microUsbInterface;
}
public void setMicroUsbInterface(MicroUsbInterface microUsbInterface) {
this.microUsbInterface = microUsbInterface;
}
}
ここでは、アダプタ モードをよりわかりやすく理解するために、携帯電話の役割を定義します。アダプタ モードでは、携帯電話は何の役割も果たしません。
アダプターを定義する
/**
* 适配器,将MicroUsb接口转成Lightning接口
*/
public class Adapter implements LightningInterface {
private MicroUsbInterface microUsbInterface;
public Adapter() {
}
public Adapter(MicroUsbInterface microUsbInterface) {
this.microUsbInterface = microUsbInterface;
}
@Override
public void chargeWithLightning() {
microUsbInterface.chargeWithMicroUsb();
}
public MicroUsbInterface getMicroUsbInterface() {
return microUsbInterface;
}
public void setMicroUsbInterface(MicroUsbInterface microUsbInterface) {
this.microUsbInterface = microUsbInterface;
}
}
このアダプターの機能は、MicroUsb を Lightning に変換することです。LightningInterface
実装方法は、対象クラスのインターフェース()を実装し、組み合わせたメソッドを使用してアダプター内にmicroUsbを定義します。次に、書き換えたchargeWithLightning()
メソッドで、microUsb のメソッドを使用して具体的な詳細を実現します。
クライアントを定義する
public class Main {
public static void main(String[] args) {
Iphone6Plus iphone6Plus = new Iphone6Plus(new AppleCharger());
iphone6Plus.charge();
System.out.println("==============================");
GalaxyS7 galaxyS7 = new GalaxyS7(new AndroidCharger());
galaxyS7.charge();
System.out.println("==============================");
Adapter adapter = new Adapter(new AndroidCharger());
Iphone6Plus newIphone = new Iphone6Plus();
newIphone.setLightningInterface(adapter);
newIphone.charge();
}
}
出力結果:
开始给我的Iphone6Plus手机充电...
使用Lightning型号的充电器充电...
结束给我的Iphone6Plus手机充电...
==============================
开始给我的GalaxyS7手机充电...
使用MicroUsb型号的充电器充电...
结束给我的GalaxyS7手机充电...
==============================
开始给我的Iphone6Plus手机充电...
使用MicroUsb型号的充电器充电...
结束给我的Iphone6Plus手机充电...
上記の例では、MicroUsb タイプの充電器を使用して、アダプターを介して iPhone を充電します。コード レベルから、MicroUsb インターフェイスとその実装クラスはアダプターを通じて再利用されます。既存のコードの大部分が再利用されます。
長所と短所
アドバンテージ
ターゲット クラスとアダプター クラスを分離し、元のコードを変更せずにアダプター クラスを導入することで既存のアダプター クラスを再利用します。
クラスの透過性と再利用性が向上し、特定の実装がアダプター クラスにカプセル化されるため、クライアント クラスに対して透過的となり、アダプターの再利用性が向上します。
柔軟性と拡張性が非常に優れており、構成ファイルを使用することで、元のコードを変更することなくアダプタを簡単に置き換えたり、新しいアダプタ クラスを追加したりすることができ、「オープンとクローズの原則」に完全に準拠しています。
欠点がある
アダプターを過度に使用すると、システムが非常に乱雑になり、全体を把握することが困難になります。たとえば、A インターフェイスが呼び出されているのは明らかですが、実際の内部実装は B インターフェイスの実装に合わせて行われており、これがシステム内で頻繁に発生すると、それは災害に等しいです。したがって、必要がなければ、アダプターを使用せずにシステムを直接リファクタリングできます。
クラスアダプターの場合、JAVA は最大 1 つのクラスを継承するため、最大 1 つのアダプタークラスを適応でき、ターゲットクラスは抽象クラスである必要があります。
要約する
構造パターンは、クラスまたはオブジェクトがどのようにグループ化されてより大きな構造を形成するかを記述します。
アダプター パターンは、インターフェイスをクライアントが必要とする別のインターフェイスに変換するために使用されます。アダプター パターンにより、互換性のないインターフェイスを持つクラスが連携できるようになり、そのエイリアスはラッパーになります。アダプター パターンは、クラス構造パターンとしてもオブジェクト構造パターンとしても使用できます。
アダプター パターンは 4 つの役割で構成されます。
ターゲット抽象クラスは、クライアントが使用するドメイン固有のインターフェイスを定義します。
アダプター クラスは、アダプターと、アダプター パターンの核となる抽象ターゲット クラスを適応させるために、別のインターフェイスをコンバーターとして呼び出すことができます。
アダプター クラスは、適応する必要がある既存のインターフェイスを定義する、適応される役割です。
クライアントクラスに対象の抽象クラスを記述し、対象の抽象クラスに定義されたビジネスメソッドを呼び出します。
オブジェクトアダプタパターンでは、アダプタクラスが対象の抽象クラスを継承(またはインタフェースを実装)してアダプタクラスのオブジェクトインスタンスを定義し、継承した対象の抽象クラスのメソッドでアダプタクラスの対応するビジネスメソッドを呼び出します。
アダプター モードの主な利点は、ターゲット クラスとアダプター クラスが分離されることで、クラスの透明性と再利用性が向上すると同時に、システムの柔軟性と拡張性が非常に優れているため、置き換えが非常に便利です。アダプターを使用するか、新しいアダプターを追加します。「[開始と終了の原則][3]」に沿って、クラス アダプター パターンの欠点は、アダプター クラスが多くのプログラミング言語で同時に複数のアダプター クラスに適応できないことです。 、オブジェクト アダプター パターンの欠点は、アダプター クラスのメソッドを置き換えるのが難しいことです。
アダプター パターンの適用には、システムが既存のクラスを使用する必要があるが、これらのクラスのインターフェイスがシステムのニーズを満たしていない、相互にあまり関連性のないいくつかのクラスで使用する再利用可能なクラスを作成したい、などがあります。仕事。