adapter-アダプタパターンの実際の例[クローズ]


84

私のチームにアダプタパターンの使用法を示したいと思います。私はオンラインでたくさんの本や記事を読みました。誰もが概念を理解するのに役立つ例(形状、メモリーカード、電子アダプターなど)を引用していますが、実際のケーススタディはありません。

アダプタパターンのケーススタディを教えてください。

ps stackoverflowで既存の質問を検索しようとしましたが、答えが見つからなかったため、新しい質問として投稿しました。これに対する答えがすでにあることがわかっている場合は、リダイレクトしてください。


4
デモをしたいのなら。あなたはあなたの環境でそれの既製の例を持っているべきです、実際にはいくつか。そうでなければ、なぜあなたはそれをデモしたいのですか?
トニーホプキンソン2012年

1
ここにいくつかの例があります。stackoverflow.com/questions/1673841/...
R4。

1
@TonyHopkinsonの目的は、実際の例を使用して、このデザインパターンを人々に認識させることです。
aksharRoop 2012年

10
@AksharRoop。デザインパターンは、問題を探す解決策ではなく、問題の解決策となることを目的としています。最良の例は、あなた自身の「世界」にあるものです。
トニーホプキンソン2012年

1
@TonyHopkinsonここでは間違った用語のデモンストレーションを使用した可能性がありますが、私が意味したのは、このパターンの概念を良い例で説明することでした。私は...私は自分のシステム内の1つを見つける必要があります同意
AksharRoop

回答:


77

アダプターの多くの例は、取るに足らないまたは非現実的です(Rectangle vs. LegacyRectangle、Ratchet vs. SocketSquarePeg vs RoundPegDuck vs. Turkey)。さらに悪いことに、多くの場合、異なるアダプタの複数のアダプタが表示されません(アダプタパターンの例としてJavaのArrays.asListを引用した人がいます)。1つのクラスのみのインターフェースを別のクラスと連携するように適合させることは、GoFアダプターパターンの弱い例のようです。このパターンは継承とポリモーフィズムを使用するため、さまざまなアダプターのアダプターの複数の実装を示す良い例が期待されます。

最良の例私が見つけたは、の第26章にあるオブジェクト指向分析設計と反復的な開発(第3版)に入門:UMLとパターンを適用します。次の画像は、本のFTPサイトで提供されているインストラクターの資料からのものです。

1つ目は、機能的に類似しているがAPIが異なる複数の実装(アダプター)をアプリケーションがどのように使用できるかを示しています(たとえば、税計算機、会計モジュール、クレジット認証サービスなど)。ドメインレイヤーコードをハードコーディングして、税金の計算、販売後の販売、クレジットカードリクエストの承認など、さまざまな方法を処理することは避けたいと考えています。これらはすべて外部モジュールであり、変更することはできません。コード。アダプターを使用すると、アダプターでハードコーディングを行うことができますが、ドメインレイヤーコードは常に同じインターフェイス(IWhateverAdapterインターフェイス)を使用します。

図26.1

上の図には、実際の適応者は表示されていません。ただし、次の図はpostSale(...)、IAccountingAdapterインターフェースでのポリモーフィック呼び出しがどのように行われるかを示しています。これにより、SOAPを介してSAPシステムに販売が転記されます。

図26.2


セッションを使用して、この例では、(実装ではないが、完全に右、私は静力学を使用して、思う)あまりにもかなり良いです:community.sitepoint.com/t/phpunit-testing-cookies-and-sessions/...
アレハンドロ・モレノ


50

フランス人を普通の人に変える方法...

 public interface IPerson
    {
        string Name { get; set; }
    }

    public interface IFrenchPerson
    {
        string Nom { get; set; }
    }

    public class Person : IPerson
    {
        public string Name { get; set; }
    }

    public class FrenchPerson : IFrenchPerson
    {
        public string Nom { get; set; }
    }

    public class PersonService
    {
        public void PrintName(IPerson person)
        {
            Debug.Write(person.Name);
        }
    }

    public class FrenchPersonAdapter : IPerson
    {
        private readonly IFrenchPerson frenchPerson;

        public FrenchPersonAdapter(IFrenchPerson frenchPerson)
        {
            this.frenchPerson = frenchPerson;
        }

        public string Name 
        {
            get { return frenchPerson.Nom; }
            set { frenchPerson.Nom = value; }
        }
    } 

    var service = new PersonService();
    var person = new Person();
    var frenchPerson = new FrenchPerson();

    service.PrintName(person);
    service.PrintName(new FrenchPersonAdapter(frenchPerson));

19
私はフランス人で、あなたが私を本物の人間と見なしていないことに侮辱を感じます。(JK)
ZeroUltimax 2017

13
@ZeroUltimaxこのコードはケベックでコンパイルされないと確信しています。
fuhrmanator 2017年

アダプターの知識がないコーダーなら、問題を簡単に解決できたでしょう。アダプター理論の知識は、時間を節約したり、ソリューションを改善したりするのにどのように役立ちますか?メソッドだけを使用するのではなく、特別なクラスを使用することが究極のポイントですか?
Rowan Gontier 2018年

インターフェイスを制御せず、クラスの1つをサードパーティのライブラリに適合させる必要がある場合はどうなりますか?この回答の範囲外である他の多くの正当な理由。
CountZero

3
これは、私が今まで出会ったアダプタパターンの使用方法の最も面白い例であり、おそらく最も親しみやすい例の1つです。
Mass

42

インターフェイスを別のインターフェイスに変換します。

アダプターパターンの実際の例

電源を接続するために、世界中にさまざまなインターフェースがあります。アダプターを使用すると、賢明なように簡単に接続できます。

ここに画像の説明を入力してください


ここではそれに対応するいくつかのコードは次のとおりです。codeproject.com/Tips/595716/Adapter-Design-Pattern-in-Cplusplus
ラガフNavada


13

これは、analog dataへの変換をシミュレートする例ですdigit data

浮動小数点の数字データをバイナリデータに変換するアダプタを提供します。これはおそらく現実の世界では役に立たないでしょう。アダプタパターンの概念を説明するのに役立つだけです。


コード

AnalogSignal.java

package eric.designpattern.adapter;

public interface AnalogSignal {
    float[] getAnalog();

    void setAnalog(float[] analogData);

    void printAnalog();
}

DigitSignal.java

package eric.designpattern.adapter;

public interface DigitSignal {
    byte[] getDigit();

    void setDigit(byte[] digitData);

    void printDigit();
}

FloatAnalogSignal.java

package eric.designpattern.adapter;

import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FloatAnalogSignal implements AnalogSignal {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private float[] data;

    public FloatAnalogSignal(float[] data) {
        this.data = data;
    }

    @Override
    public float[] getAnalog() {
        return data;
    }

    @Override
    public void setAnalog(float[] analogData) {
        this.data = analogData;
    }

    @Override
    public void printAnalog() {
        logger.info("{}", Arrays.toString(getAnalog()));
    }
}

BinDigitSignal.java

package eric.designpattern.adapter;

import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class BinDigitSignal implements DigitSignal {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private byte[] data;

    public BinDigitSignal(byte[] data) {
        this.data = data;
    }

    @Override
    public byte[] getDigit() {
        return data;
    }

    @Override
    public void setDigit(byte[] digitData) {
        this.data = digitData;
    }

    @Override
    public void printDigit() {
        logger.info("{}", Arrays.toString(getDigit()));
    }
}

AnalogToDigitAdapter.java

package eric.designpattern.adapter;

import java.util.Arrays;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * Adapter - convert analog data to digit data.
 * </p>
 * 
 * @author eric
 * @date Mar 8, 2016 1:07:00 PM
 */
public class AnalogToDigitAdapter implements DigitSignal {
    public static final float DEFAULT_THRESHOLD_FLOAT_TO_BIN = 1.0f; // default threshold,
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private AnalogSignal analogSignal;
    private byte[] digitData;
    private float threshold;
    private boolean cached;

    public AnalogToDigitAdapter(AnalogSignal analogSignal) {
        this(analogSignal, DEFAULT_THRESHOLD_FLOAT_TO_BIN);
    }

    public AnalogToDigitAdapter(AnalogSignal analogSignal, float threshold) {
        this.analogSignal = analogSignal;
        this.threshold = threshold;
        this.cached = false;
    }

    @Override
    public synchronized byte[] getDigit() {
        if (!cached) {
            float[] analogData = analogSignal.getAnalog();
            int len = analogData.length;
            digitData = new byte[len];

            for (int i = 0; i < len; i++) {
                digitData[i] = floatToByte(analogData[i]);
            }
        }

        return digitData;
    }

    // not supported, should set the inner analog data instead,
    @Override
    public void setDigit(byte[] digitData) {
        throw new UnsupportedOperationException();
    }

    public synchronized void setAnalogData(float[] analogData) {
        invalidCache();
        this.analogSignal.setAnalog(analogData);
    }

    public synchronized void invalidCache() {
        cached = false;
        digitData = null;
    }

    @Override
    public void printDigit() {
        logger.info("{}", Arrays.toString(getDigit()));
    }

    // float -> byte convert,
    private byte floatToByte(float f) {
        return (byte) (f >= threshold ? 1 : 0);
    }
}

コード-テストケース

AdapterTest.java

package eric.designpattern.adapter.test;

import java.util.Arrays;

import junit.framework.TestCase;

import org.junit.Test;

import eric.designpattern.adapter.AnalogSignal;
import eric.designpattern.adapter.AnalogToDigitAdapter;
import eric.designpattern.adapter.BinDigitSignal;
import eric.designpattern.adapter.DigitSignal;
import eric.designpattern.adapter.FloatAnalogSignal;

public class AdapterTest extends TestCase {
    private float[] analogData = { 0.2f, 1.4f, 3.12f, 0.9f };
    private byte[] binData = { 0, 1, 1, 0 };
    private float[] analogData2 = { 1.2f, 1.4f, 0.12f, 0.9f };

    @Test
    public void testAdapter() {
        AnalogSignal analogSignal = new FloatAnalogSignal(analogData);
        analogSignal.printAnalog();

        DigitSignal digitSignal = new BinDigitSignal(binData);
        digitSignal.printDigit();

        // adapter
        AnalogToDigitAdapter adAdapter = new AnalogToDigitAdapter(analogSignal);
        adAdapter.printDigit();
        assertTrue(Arrays.equals(digitSignal.getDigit(), adAdapter.getDigit()));

        adAdapter.setAnalogData(analogData2);
        adAdapter.printDigit();
        assertFalse(Arrays.equals(digitSignal.getDigit(), adAdapter.getDigit()));
    }
}

依存-Maven経由

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.2</version>
    </dependency>

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.13</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.13</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.16</version>
    </dependency>

テストする方法

ユニットテストを実行するだけです。


7

アダプタパターンは、互換性のない2つのインターフェイス間のブリッジとして機能します。このパターンには、2つの独立したインターフェースまたは互換性のないインターフェース間の通信を担当するアダプターと呼ばれる単一のクラスが含まれます。

実際の例としては、言語翻訳者やモバイル充電器などがあります。このyoutubeビデオの詳細:

Youtube-アダプタデザインパターン:はじめに


3

動作が似ているさまざまなインターフェイスを処理する必要がある場合は、アダプタデザインパターンを使用できます(通常、動作は似ているがメソッドが異なるクラスを意味します)。その一例は、Samsung TVに接続するクラスと、SonyTVに接続するクラスです。これらは、メニューを開く、再生を開始する、ネットワークに接続するなどの共通の動作を共有しますが、ライブラリごとに異なる実装があります(メソッド名と署名が異なります)。これらのさまざまなベンダー固有の実装は、UML図ではAdapteeと呼ばれます。

したがって、コード(UML図ではクライアントと呼ばれます)では、各ベンダー(またはAdaptee)のメソッド呼び出しをハードコードする代わりに、これらの同様の動作をラップして機能する汎用インターフェイス(UML図ではターゲットと呼ばれます)を作成できます。オブジェクトのタイプは1つだけです。

アダプタは、次に実装するターゲットをにそのメソッド呼び出しを委任するインタフェースAdapteesに渡されるアダプタコンストラクタを介して。

これをJavaコードで実現するために、アダプターを使用して複数のスマートTVインターフェースを処理する上記とまったく同じ例を使用して、非常に単純なプロジェクトを作成しました。コードは小さく、十分に文書化されており、自明なので、実際の実装がどのように見えるかを調べてください。

コードをダウンロードして、MavenプロジェクトとしてEclipse(またはお気に入りのIDE)にインポートするだけです。org.example.Main.javaを実行してコードを実行できます。ここで重要なことは、クラスとインターフェイスを組み合わせてパターンを設計する方法を理解することです。また、com.thirdparty.libsパッケージに偽のAdapteeをいくつか作成しました。それが役に立てば幸い!

https://github.com/Dannemann/java-design-patterns


2

実際の例の1つはQt-Dbusです。

qt-dbusには、提供されたxmlファイルからアダプターとインターフェースコードを生成するユーティリティがあります。これを行う手順は次のとおりです。

 1. Create the xml file - this xml file should have the interfaces 
that can be viewed by the qdbus-view in the system either on 
the system or session bus.

    2.With the utility - qdbusxml2cpp , you generate the interface adaptor code. 
This interface adaptor does the demarshalling of the data that is 
received from the client. After demarshalling, it invokes the 
user defined - custom methods ( we can say as adaptee).

    3. At the client side, we generate the interface from the xml file. 
This interface is invoked by the client. The interface does the 
marshalling of the data and invokes the adaptor interface. As told 
in the point number 2, the adaptor interface does the demarshalling 
and calls the adaptee - user defined methods.

Qt-Dbusの完全な例はここで見ることができます-

http://www.tune2wizard.com/linux-qt-signals-and-slots-qt-d-bus/


2

インジェクション攻撃に対する防御として使用されるアダプタパターンのPHP実装は、次の場所にあります。

http://www.php5dp.com/category/design-patterns/adapter-composition/

アダプタパターンの興味深い側面の1つは、多重継承に依存するクラスアダプタと構成に依存するオブジェクトアダプタの2つの種類があることです。上記の例は、構成に依存しています。


リンクphp5dp.com/category/design-patterns/adapter-composition は機能しなくなりました
FantomX 18

2

アダプタデザインパターンは、1つのクラスのインターフェイスをクライアントが期待するインターフェイスに変換するのに役立ちます。

例: 都市名を入力値として渡すことにより、天気(摂氏)を返すサービスがあります。ここで、クライアントが郵便番号を入力として渡し、その見返りに都市の気温を期待していると仮定します。ここでは、これを実現するためのアダプターが必要です。

public interface IWetherFinder {
    public double getTemperature(String cityName);
}

class WeatherFinder implements IWetherFinder{
   @Override
   public double getTemperature(String cityName){
     return 40;
   }
}

interface IWeatherFinderClient
{
   public double getTemperature(String zipcode);
}  

public class WeatherAdapter implements IWeatherFinderClient {

    @Override
    public double getTemperature(String zipcode) {

        //method to get cityname by zipcode 
        String cityName = getCityName(zipcode);

        //invoke actual service
        IWetherFinder wetherFinder = new WeatherFinder();
        return wetherFinder.getTemperature(cityName);
    }

    private String getCityName(String zipCode) {
        return "Banaglore";
    }
}

0

実際の例は、アプリケーション内のドキュメントのレポートです。ここにあるような単純なコード。

アダプターはプログラミング構造に非常に役立つと思います。

class WordAdaptee implements IReport{
    public void report(String s) {
        System.out.println(s +" Word");
    }
}

class ExcellAdaptee implements IReport{
    public void report(String s) {
        System.out.println(s +" Excel");
    }
}


class ReportAdapter implements IReport{
    WordAdaptee wordAdaptee=new WordAdaptee();
    @Override
    public void report(String s) {
        wordAdaptee.report(s);
    }
}

interface IReport {
    public void report(String s);
}

public class Main {
    public static void main(String[] args) {

        //create the interface that client wants
        IReport iReport=new ReportAdapter();

        //we want to write a report both from excel and world
        iReport.report("Trial report1 with one adaptee");  //we can directly write the report if one adaptee is avaliable 

        //assume there are N adaptees so it is like in our example
        IReport[] iReport2={new ExcellAdaptee(),new WordAdaptee()};

        //here we can use Polymorphism here  
        for (int i = 0; i < iReport2.length; i++) {
            iReport2[i].report("Trial report 2");
        }
    }
}

結果は次のようになります。

Trial report1 with one adaptee Word
Trial report 2 Excel
Trial report 2 Word

1
これは実際にはプロキシです。アダプターとアダプターのインターフェースは異なります。それらは同じインターフェースを実装していません。それがプロキシが行うことです。
dvallejo 2015

これはアダプタパターンではありません。アダプタパターンは、被適応者が実装していないターゲットインターフェイスを実装するために使用されます。
FedericoG

0

変更できないが使用する必要のあるインターフェースがある場合は、アダプターを使用します。あなたがオフィスの新しい男であり、白髪をあなたの規則に従わせることができないので、それを見てください-あなたは彼らの規則に適応しなければなりません。これは、ユーザーインターフェイスが指定されているときに私が取り組んだ実際のプロジェクトの実際の例です。

ファイル内のすべての行をリストデータ構造に読み込み、グリッドに表示するアプリケーションがあります(基になるデータストアインターフェイスをIDataStoreと呼びましょう)。ユーザーは、「最初のページ」、「前のページ」、「次のページ」、「最後のページ」のボタンをクリックして、これらのデータをナビゲートできます。すべてが正常に動作します。

ここで、アプリケーションは、メモリに読み込むには大きすぎる本番ログで使用する必要がありますが、ユーザーはそれをナビゲートする必要があります。1つの解決策は、最初のページ、次のページ、前のページ、最後のページを格納するキャッシュを実装することです。ユーザーが[次のページ]をクリックすると、キャッシュからページが返され、キャッシュが更新されます。最後のページをクリックすると、キャッシュから最後のページが返されます。バックグラウンドでは、すべての魔法を実行するファイルストリームがあります。そうすることで、ファイル全体ではなく、メモリに4ページしかありません。

アダプターを使用して、ユーザーが気付かないうちにこの新しいキャッシュ機能をアプリケーションに追加できます。現在のIDataStoreを拡張し、それをCacheDataStoreと呼びます。ロードするファイルが大きい場合は、CacheDataStoreを使用します。First、Next、Previous、Lastページをリクエストすると、情報はキャッシュにルーティングされます。

そして、誰が知っているか、明日、上司はデータベーステーブルからファイルを読み始めたいと思っています。キャッシュの場合と同じように、IDataStoreをSQLDataStoreに拡張し、バックグラウンドで接続をセットアップするだけです。[次のページ]をクリックすると、データベースから次の数百行をフェッチするために必要なSQLクエリが生成されます。

基本的に、アプリケーションの元のインターフェイスは変更されていません。従来のインターフェースを維持しながら、モダンでクールな機能を採用して機能させました。


わからない?既存のインターフェースを使用してメソッドを実装したようですね。適応する必要のあるさまざまなインターフェースとアダプタークラスはどこにありますか?
berimbolo 2017

@berimbolo上記の例ではアダプタパターンについて明確に説明されていないため、混乱は有効です。
rahil008 2017

0

@Justice oの例では、アダプターパターンについて明確に説明していません。彼の答えを拡張する-コンシューマーコードが使用する既存のインターフェイスIDataStoreがあり、変更することはできません。ここで、実装したいことを実行するXYZライブラリのクールな新しいクラスを使用するように求められますが、そのクラスを変更してIDataStoreを拡張することはできません。すでに問題が発生していますか?コンシューマーコードが期待するインターフェイス(IDataStore)を実装する新しいクラス(ADAPTER)を作成し、必要な機能を備えたライブラリのクラスを使用することで(ADAPTEE)、ADAPTERのメンバーとして目的を達成できます。



0

Yiiフレームワークの例は次のとおりです。YiiはインターフェイスICacheを利用して内部キャッシュを使用します。 https://www.yiiframework.com/doc/api/1.1/ICache

その署名は次のようなものです:-

abstract public boolean set(string $id, mixed $value, integer $expire=0, ICacheDependency $dependency=NULL)
abstract public mixed get(string $id)

たとえば、Yiiサービスコンポーネント(サービスロケーター)構成https:/でこのサービスを定義することにより、Yiiプロジェクト内でsymfonyキャッシュライブラリhttps://packagist.org/packages/symfony/cacheとそのキャッシュインターフェイス を使用したいとし ます。 /github.com/symfony/cache-contracts/blob/master/CacheInterface.php

    public function get(string $key, callable $callback, float $beta = null, array &$metadata = null);

Symfonyは2番目の呼び出し可能パラメーターを提供するときにgetメソッドをセッターとしても使用するため、symfonyキャッシュにはgetメソッドのみのインターフェイスがあり、setメソッドとgetメソッドの異なる署名がありません。

Yiiコアは内部でこのYiiキャッシュ/インターフェースを使用するため、場所で不可能ではないにしても、そのインターフェースへの呼び出しを書き換えることは困難です(Yii / YiiBaseを拡張します)。

さらに、Symfonyキャッシュは私たちのクラスでもないので、Yiiキャッシュインターフェイスに合うようにインターフェイスを書き直すことはできません。

それで、ここに救助するアダプターパターンが来ます。マッピング= Yiiキャッシュインターフェース呼び出しをSymfonyキャッシュインターフェースにマッピングする中間アダプターを記述します

このようになります

    class YiiToSymfonyCacheAdapter implements \Yii\system\caching\ICache
    {
        private \Symfony\Contracts\Cache\CacheInterface $symfonyCache;

        public function __construct(\Symfony\Contracts\Cache\CacheInterface $symfonyCache)
        {
            $this->symfonyCache = $symfonyCache;
        }

      
      public boolean set(string $id, mixed $value, integer $expire=0, ICacheDependency 
       $dependency=NULL) 
      {

          // https://symfony.com/doc/current/cache.html
          return $this->symfonyCache->get(
              $id, 
              function($item) { 
              // some logic .. 
               return $value; 
              }
          );

//          https://github.com/symfony/cache/blob/master/Adapter/MemcachedAdapter.php
// if a class could be called statically, the adapter could call statically also eg. like this
//          return \Symfony\Component\Cache\Adapter\MemcacheAdapter::get(
//              $id, 
//              function($item) { 
//              // some logic .. 
//               return $value; 
//              }
          );
       }

       public mixed get(string $id) 
       {
           // https://github.com/symfony/cache/blob/master/Adapter/FilesystemAdapter.php 
           // if a class could be called statically, the adapter could call statically also eg. like this
           // \Symfony\Component\Cache\Adapter\FileSystemAdapter::get($id)
           return $this->symfonyCache->get($id) 
       }
    } 


-1

これは、アダプターの実装例です。

interface NokiaInterface {
    chargementNokia(x:boolean):void
}


class SamsungAdapter implements NokiaInterface {
//nokia chargement adapted to samsung
    chargementNokia(x:boolean){
        const old= new SamsungCharger();
        let y:number = x ? 20 : 1;
        old.charge(y);
      }
}


class SamsungCharger {
      charge(x:number){
            console.log("chrgement x ==>", x);
      }
}


function main() {
      //charge samsung with nokia charger
      const adapter = new SamsungAdapter();
      adapter.chargementNokia(true);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.