Adapter - Jedes echte Beispiel für ein Adaptermuster [geschlossen]

84

Ich möchte meinem Team die Verwendung des Adaptermusters demonstrieren . Ich habe viele Bücher und Artikel online gelesen. Jeder zitiert ein Beispiel, das nützlich ist, um das Konzept zu verstehen (Form, Speicherkarte, elektronischer Adapter usw.), aber es gibt keine wirkliche Fallstudie.

Können Sie bitte eine Fallstudie zum Adaptermuster teilen?

ps Ich habe versucht, vorhandene Fragen zu stackoverflow zu durchsuchen, aber die Antwort nicht gefunden, sodass ich sie als neue Frage poste. Wenn Sie wissen, dass es bereits eine Antwort darauf gibt, leiten Sie diese bitte weiter.

AksharRoop
quelle
4
Nun, wenn Sie es demonstrieren möchten. Sie sollten ein fertiges Beispiel dafür in Ihrer Umgebung haben, tatsächlich mehrere. Warum sollten Sie es sonst demonstrieren?
Tony Hopkinson
1
Einige Beispiele hier. stackoverflow.com/questions/1673841/…
r4.
1
@TonyHopkinson Ziel ist es, die Menschen anhand eines echten Beispiels auf dieses Designmuster aufmerksam zu machen.
AksharRoop
10
@AksharRoop. Design Pattern soll eine Lösung für ein Problem sein, keine Lösung, die nach einem Problem sucht. Bestes Beispiel ist eines in Ihrer eigenen "Welt".
Tony Hopkinson
1
@TonyHopkinson Ich habe hier möglicherweise einen falschen Begriff verwendet, um zu demonstrieren, aber ich wollte das Konzept dieses Musters mit einem guten Beispiel erklären. Ich bin damit einverstanden, dass ich die in meinem eigenen System finden sollte ...
AksharRoop

Antworten:

77

Viele Beispiele für Adapter sind trivial oder unrealistisch ( Rectangle vs. LegacyRectangle, Ratchet vs. Socket , SquarePeg vs. RoundPeg , Duck vs. Turkey ). Schlimmer noch, viele zeigen nicht mehrere Adapter für verschiedene Adapter an ( jemand zitierte Javas Arrays.asList als Beispiel für das Adaptermuster ). Die Anpassung einer Schnittstelle nur einer Klasse an die Arbeit mit einer anderen Klasse scheint ein schwaches Beispiel für das GoF-Adaptermuster zu sein. Dieses Muster verwendet Vererbung und Polymorphismus, so dass man erwarten würde, dass ein gutes Beispiel mehrere Implementierungen von Adaptern für verschiedene Adapter zeigt .

Das beste Beispiel, das ich gefunden habe, ist in Kapitel 26 von Anwenden von UML und Mustern: Eine Einführung in die objektorientierte Analyse und das Design und die iterative Entwicklung (3. Ausgabe) . Die folgenden Bilder stammen aus dem Lehrermaterial, das auf einer FTP-Site für das Buch bereitgestellt wird.

Die erste zeigt, wie eine Anwendung mehrere Implementierungen (Adaptees) verwenden kann, die funktional ähnlich sind (z. B. Steuerrechner, Buchhaltungsmodule, Kreditautorisierungsdienste usw.), jedoch unterschiedliche APIs haben. Wir möchten vermeiden, unseren Domain-Layer-Code fest zu codieren, um die verschiedenen Möglichkeiten zur Berechnung von Steuern, Nachverkäufen, Autorisierung von Kreditkartenanfragen usw. zu handhaben. Dies sind alles externe Module, die variieren können und für die wir den nicht ändern können Code. Mit dem Adapter können wir die Hardcodierung im Adapter durchführen, während unser Domänenschichtcode immer dieselbe Schnittstelle verwendet (die IWhateverAdapter-Schnittstelle).

Abb. 26.1

In der obigen Abbildung sehen wir nicht die tatsächlichen Adaptees. Die folgende Abbildung zeigt jedoch, wie ein polymorpher Aufruf postSale(...)in der IAccountingAdapter-Schnittstelle erfolgt, der zu einer Buchung des Verkaufs über SOAP an ein SAP-System führt.

Abb. 26.2

Fuhrmanator
quelle
Dieses Beispiel mit Sessions ist auch ziemlich gut (obwohl die Implementierung mit Statics meiner Meinung nach nicht ganz richtig ist): community.sitepoint.com/t/phpunit-testing-cookies-and-sessions/…
Alejandro Moreno
und natürlich die Implementierung in PHP: github.com/alex-moreno/DesignPatternsPHP/tree/master/Adapter
Alejandro Moreno
50

Wie man aus einer französischen Person eine normale Person macht ...

 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; }
        }
    } 

Beispiel

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

    service.PrintName(person);
    service.PrintName(new FrenchPersonAdapter(frenchPerson));
CountZero
quelle
19
Ich bin Franzose und ich fühle mich beleidigt, dass Sie mich nicht als echte Person betrachten. (JK)
ZeroUltimax
13
@ZeroUltimax Ich bin mir ziemlich sicher, dass dieser Code in Quebec nicht kompiliert werden kann.
Fuhrmanator
Jeder Codierer ohne Kenntnis der Adapter hätte das Problem leicht gelöst. Wie hilft die Kenntnis der Adaptertheorie, Zeit zu sparen oder die Lösung zu verbessern? Ist es der ultimative Punkt, eine spezielle Klasse zu verwenden, anstatt nur eine Methode zu verwenden?
Rowan Gontier
Was ist, wenn Sie die Benutzeroberfläche nicht steuern und eine Ihrer Klassen an eine Bibliothek eines Drittanbieters anpassen müssen? Viele andere gute Gründe, die außerhalb des Rahmens dieser Antwort liegen.
CountZero
3
Dies ist das lustigste - und möglicherweise eines der zugänglichsten - Beispiele für die Verwendung des Adaptermusters, auf das ich jemals gestoßen bin.
Mass Dot Net
13

Hier ist ein Beispiel, das die Konvertierung analog datain simuliert digit data.

Es bietet einen Adapter, der Float-Digit-Daten in Binärdaten konvertiert. In der realen Welt ist es wahrscheinlich nicht nützlich. Es hilft nur, das Konzept des Adaptermusters zu erklären.


Code

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);
    }
}

Code - Testfall

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()));
    }
}

Abhängigkeit - über 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>

Wie zu testen

Führen Sie einfach den Unit-Test durch.

Eric Wang
quelle
7

Das Adaptermuster fungiert als Brücke zwischen zwei inkompatiblen Schnittstellen. Dieses Muster umfasst eine einzelne Klasse namens Adapter, die für die Kommunikation zwischen zwei unabhängigen oder inkompatiblen Schnittstellen verantwortlich ist.

Beispiele aus der Praxis könnten ein Sprachübersetzer oder ein mobiles Ladegerät sein. Mehr hier in diesem Youtube-Video:

Youtube - Adapter Design Pattern: Einführung

babu
quelle
3

Sie können das Adapter-Entwurfsmuster verwenden, wenn Sie mit verschiedenen Schnittstellen mit ähnlichem Verhalten arbeiten müssen (was normalerweise Klassen mit ähnlichem Verhalten, aber mit unterschiedlichen Methoden bedeutet). Ein Beispiel hierfür wäre eine Klasse zum Anschließen an ein Samsung-Fernsehgerät und eine andere zum Anschließen an ein Sony-Fernsehgerät. Sie haben ein gemeinsames Verhalten wie das Öffnen des Menüs, das Starten der Wiedergabe, das Herstellen einer Verbindung zu einem Netzwerk usw., aber jede Bibliothek hat eine andere Implementierung (mit unterschiedlichen Methodennamen und Signaturen). Diese verschiedenen herstellerspezifischen Implementierungen werden in den UML-Diagrammen als Adaptee bezeichnet .

In Ihrem Code ( in den UML-Diagrammen Client genannt ) können Sie anstelle von Hardcode für die Methodenaufrufe jedes Anbieters (oder Adaptees ) eine generische Schnittstelle ( in UML-Diagrammen Target genannt ) erstellen, um diese ähnlichen Verhaltensweisen und Funktionen zu verpacken mit nur einem Objekttyp.

Die Adapter werden dann die Umsetzung Ziel Schnittstelle seine Methodenaufrufe an die Delegierung Adaptees , die an die übergeben werden Adapter über Konstruktor.

Damit Sie dies in Java-Code realisieren können, habe ich ein sehr einfaches Projekt geschrieben, das genau das oben erwähnte Beispiel verwendet und Adapter verwendet, um mit mehreren Smart-TV-Schnittstellen umzugehen. Der Code ist klein, gut dokumentiert und selbsterklärend. Sehen Sie sich also an, wie eine Implementierung in der realen Welt aussehen würde.

Laden Sie einfach den Code herunter und importieren Sie ihn als Maven-Projekt in Eclipse (oder Ihre Lieblings-IDE). Sie können den Code ausführen, indem Sie org.example.Main.java ausführen . Denken Sie daran, dass es hier wichtig ist zu verstehen, wie Klassen und Schnittstellen zusammengesetzt werden, um das Muster zu entwerfen. Ich habe auch einige gefälschte Adaptees im Paket com.thirdparty.libs erstellt . Ich hoffe es hilft!

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

Jaabax
quelle
2

Ein echtes Beispiel ist Qt-Dbus.

Der qt-dbus verfügt über ein Dienstprogramm zum Generieren des Adapter- und Schnittstellencodes aus der bereitgestellten XML-Datei. Hier sind die Schritte dazu.

 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.

Das vollständige Beispiel für Qt-Dbus finden Sie hier -

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

geschickt
quelle
2

Eine PHP-Implementierung des Adaptermusters zur Abwehr von Injektionsangriffen finden Sie hier:

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

Einer der interessanten Aspekte des Adaptermusters besteht darin, dass es zwei Varianten gibt: einen Klassenadapter, der auf Mehrfachvererbung basiert, und einen Objektadapter, der auf Komposition basiert. Das obige Beispiel beruht auf der Zusammensetzung.

Rechnung
quelle
Der Link php5dp.com/category/design-patterns/adapter-composition funktioniert nicht mehr
FantomX1
2

Adapterdesignmuster helfen beim Konvertieren der Schnittstelle einer Klasse in die Schnittstelle der Client-Erwartungen.

Beispiel: Sie haben einen Dienst, der das Wetter (in Celsius) zurückgibt, indem Sie den Städtenamen als Eingabewert übergeben. Angenommen, Ihr Kunde möchte die Postleitzahl als Eingabe übergeben und erwartet im Gegenzug die Temperatur der Stadt. Hier benötigen Sie einen Adapter, um dies zu erreichen.

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";
    }
}
Sumanth Varada
quelle
0

Ein reales Beispiel kann das Melden von Dokumenten in einer Anwendung sein. Einfacher Code wie hier.

Adapter sind meiner Meinung nach sehr nützlich für die Programmierstruktur.

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");
        }
    }
}

Ergebnisse werden sein:

Trial report1 with one adaptee Word
Trial report 2 Excel
Trial report 2 Word
Huseyin
quelle
1
Dies ist eigentlich ein Proxy. Ein Adapter und ein Adapter haben unterschiedliche Schnittstellen. Sie implementieren nicht dieselbe Schnittstelle. Das macht ein Proxy.
Dvallejo
Dies ist nicht das Adaptermuster. Das Adaptermuster wird verwendet, um eine Zielschnittstelle zu implementieren, die der Adapter nicht implementiert.
FedericoG
0

Verwenden Sie den Adapter, wenn Sie eine Schnittstelle haben, die Sie nicht ändern können, die Sie jedoch verwenden müssen. Sehen Sie es so, als wären Sie der neue Mann in einem Büro und Sie können die grauen Haare nicht dazu bringen, Ihren Regeln zu folgen - Sie müssen sich an ihre anpassen. Hier ist ein echtes Beispiel aus einem echten Projekt, an dem ich irgendwann gearbeitet habe, wo die Benutzeroberfläche eine Selbstverständlichkeit ist.

Sie haben eine Anwendung, die alle Zeilen in einer Datei in eine Listendatenstruktur einliest und in einem Raster anzeigt (nennen wir die zugrunde liegende Datenspeicherschnittstelle IDataStore). Der Benutzer kann durch diese Daten navigieren, indem er auf die Schaltflächen "Erste Seite", "Vorherige Seite", "Nächste Seite", "Letzte Seite" klickt. Alles funktioniert gut.

Jetzt muss die Anwendung mit Produktionsprotokollen verwendet werden, die zu groß sind, um in den Speicher eingelesen zu werden, aber der Benutzer muss immer noch darin navigieren! Eine Lösung wäre, einen Cache zu implementieren, in dem die erste Seite, die nächste, die vorherige und die letzte Seite gespeichert werden. Wenn der Benutzer auf "Nächste Seite" klickt, wird die Seite aus dem Cache zurückgegeben und der Cache aktualisiert. Wenn sie auf die letzte Seite klicken, wird die letzte Seite aus dem Cache zurückgegeben. Im Hintergrund haben wir einen Filestream, der die ganze Magie macht. Auf diese Weise haben wir im Gegensatz zur gesamten Datei nur vier Seiten im Speicher.

Sie können einen Adapter verwenden, um diese neue Cache-Funktion zu Ihrer Anwendung hinzuzufügen, ohne dass der Benutzer dies bemerkt. Wir erweitern den aktuellen IDataStore und nennen ihn CacheDataStore. Wenn die zu ladende Datei groß ist, verwenden wir CacheDataStore. Wenn wir die ersten, nächsten, vorherigen und letzten Seiten anfordern, werden die Informationen an unseren Cache weitergeleitet.

Und wer weiß, morgen möchte der Chef anfangen, die Dateien aus einer Datenbanktabelle zu lesen. Alles, was Sie tun, ist, IDataStore wie für Cache auf SQLDataStore zu erweitern und die Verbindung im Hintergrund einzurichten. Wenn sie auf Nächste Seite klicken, generieren Sie die erforderliche SQL-Abfrage, um die nächsten paar hundert Zeilen aus der Datenbank abzurufen.

Im Wesentlichen hat sich die ursprüngliche Oberfläche der Anwendung nicht geändert. Wir haben einfach moderne und coole Funktionen angepasst, um sie zu verwenden und gleichzeitig die alte Benutzeroberfläche beizubehalten.

Gerechtigkeit O.
quelle
Ich verstehe nicht? Klingt es so, als hätten Sie gerade eine vorhandene Schnittstelle verwendet und die Methoden implementiert? Wo ist die unterschiedliche Schnittstelle, an die Sie sich anpassen müssen, und die Adapterklasse?
Berimbolo
@berimbolo Ihre Verwirrung ist gültig, da das obige Beispiel nicht klar über das Adaptermuster spricht.
Rahil008
0

Das Beispiel von @Justice o spricht nicht klar über das Adaptermuster. Erweiterung seiner Antwort - Wir haben eine vorhandene Schnittstelle IDataStore, die unser Consumer-Code verwendet, und können diese nicht ändern. Jetzt werden wir gebeten, eine coole neue Klasse aus der XYZ-Bibliothek zu verwenden, die das tut, was wir implementieren möchten, aber wir können diese Klasse nicht ändern, um unseren IDataStore zu erweitern. Haben Sie das Problem bereits gesehen? Erstellen einer neuen Klasse - ADAPTER, die die Schnittstelle implementiert, die unser Consumer-Code erwartet, dh IDataStore, und durch Verwendung der Klasse aus der Bibliothek, deren Funktionen wir benötigen - ADAPTEE, als Mitglied in unserem ADAPTER, können wir erreichen, was wir wollten.

rahil008
quelle
0

Ein Beispiel aus dem Yii-Framework wäre: Yii verwendet den internen Cache unter Verwendung eines Schnittstellen-ICache. https://www.yiiframework.com/doc/api/1.1/ICache

deren Unterschrift ist wie: -

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

Angenommen, Sie möchten in einem Yii-Projekt die Symfony-Cache-Bibliothek https://packagist.org/packages/symfony/cache mit ihrer Cache-Schnittstelle verwenden, indem Sie diesen Dienst in der Konfiguration der Yii-Dienstkomponenten (Service Locator) https: / definieren /github.com/symfony/cache-contracts/blob/master/CacheInterface.php

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

Wir sehen, dass der Symfony-Cache eine Schnittstelle mit nur einer get-Methode hat, bei der eine set-Methode und eine andere Signatur für eine get-Methode fehlen, da Symfony die get-Methode auch als Setter verwendet, wenn der zweite aufrufbare Parameter angegeben wird.

Da der Yii-Kern diesen Yii-Cache / diese Yii-Schnittstelle intern verwendet, ist es schwierig (Erweiterung von Yii / YiiBase), wenn nicht an bestimmten Stellen unmöglich, die Aufrufe an diese Schnittstelle neu zu schreiben.

Außerdem ist der Symfony-Cache weder unsere Klasse, sodass wir die Schnittstelle nicht so umschreiben können, dass sie zur Yii-Cache-Oberfläche passt.

Hier kommt also das Adaptermuster zur Rettung. Wir werden ein Mapping = einen Zwischenadapter schreiben, der die Aufrufe der Yii-Cache-Schnittstelle der Symfony-Cache-Schnittstelle zuordnet

Würde so aussehen

    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) 
       }
    } 

FantomX1
quelle
-1

Dies ist ein Beispiel für die Adapterimplementierung:

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);
}
Omar Marzougui
quelle