адаптер - любой реальный пример шаблона адаптера

Я хочу продемонстрировать использование Шаблон Адаптер мои команды. Я прочитал много книг и статей в интернете. Каждый приводит пример, который полезен для понимания концепции (форма, карта памяти, электронный адаптер и т. д.), но нет никакого реального исследования.

можете ли вы поделиться любым примером шаблона адаптера?

p.s. Я попытался найти существующие вопросы в stackoverflow, но не нашел ответа, поэтому разместил его как новый вопрос. Если вы знайте, что на это уже есть ответ, тогда, пожалуйста, перенаправьте.

12 ответов


многие примеры адаптера тривиальны или нереалистичны (прямоугольник против LegacyRectangle, храповик против сокета, SquarePeg против RoundPeg, утка против индейки). Хуже того, многие не показывают несколько адаптеров для различных адаптеров (кто-то процитировал массивы Java.asList в качестве примера шаблона адаптера). Адаптация интерфейса только один класс для работы с другим кажется слабым примером адаптера GoF узор. Этот шаблон использует наследование и полиморфизм, поэтому можно было бы ожидать, что хороший пример покажет несколько реализаций адаптеров для разных adaptees.

на лучший пример я нашел это в главе 26 применение UML и шаблонов: введение в объектно-ориентированный анализ и проектирование и итеративное развитие (3-е издание). Следующие образы из материала инструктор на FTP-сайт для книги.

первый показывает, как приложение может использовать несколько реализаций (адаптеров), которые функционально похожи (например, налоговые калькуляторы, бухгалтерские модули, услуги авторизации кредитов и т. д.), но имеют разные API. Мы хотим избежать жесткого кодирования нашего кода уровня домена для обработки различных возможных способов расчета налогов, почтовых продаж, авторизации запросов кредитных карт и т. д. Это все внешние модули, которые могут отличаться и для которых мы не можем изменить код. Адаптер позволяет нам выполнять жесткое кодирование в адаптере, тогда как наш код уровня домена всегда использует один и тот же интерфейс (интерфейс IWhateverAdapter).

Fig. 26.1

мы не видим на рисунке выше фактической adaptees. Однако, на следующем рисунке показано, как полиморфный вызов postSale(...) в интерфейсе IAccountingAdapter производится, что приводит к разноске продажи через SOAP в систему SAP.

Fig. 26.2


преобразование интерфейса в другой интерфейс.

любой реальный пример шаблона адаптера

для того чтобы соединить силу, мы имеем различные интерфейсы во всем мире. Используя адаптер, мы можем легко подключиться, как wise.

enter image description here


Как превратить французского человека в нормального человека...

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

вот пример, который имитирует преобразования analog data to 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>

Как проверить

просто запустите модульный тест.


шаблон адаптера работает как мост между двумя несовместимыми интерфейсами. Этот шаблон включает в себя один класс, называемый адаптер, который отвечает за связь между двумя независимыми и несовместимыми межфазные границы.

реальными примерами могут быть переводчик языка или мобильное зарядное устройство. Подробнее здесь, в этом видео youtube:

Youtube-адаптер шаблон дизайна: введение


вы можете найти PHP-реализацию шаблона адаптера, используемого в качестве защиты от инъекционных атак здесь:

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

одним из интересных аспектов шаблона адаптера является то, что он поставляется в двух вариантах: адаптер класса, полагающийся на множественное наследование, и адаптер объекта, полагающийся на композицию. Приведенный выше пример основан на композиции.


одним из реальных примеров является 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/


реальным примером могут быть отчетные документы в приложении. Простой код, как здесь.

адаптеры, я думаю, очень полезны для программирования структуры.

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

вы можете использовать шаблон проектирования адаптера, когда вам приходится иметь дело с различными интерфейсами с аналогичным поведением (что обычно означает классы с аналогичным поведением, но с разными методами). Примером этого может быть класс для подключения к телевизору Samsung и еще один для подключения к телевизору Sony. Они будут делиться общим поведением, таким как open menu, start playback, connect to a network и т. д., Но каждая библиотека будет иметь другую реализацию (с разными именами методов и подписывание.) Эти различные реализации конкретного поставщика называются Adaptee на диаграммах UML.

Итак, в вашем коде (называется клиент в UML-диаграммах) вместо жесткого кода вызывается метод каждого поставщика (или Adaptee), затем вы можете создать общий интерфейс (называемый цель в UML-диаграммах), чтобы обернуть эти аналогичные поведения и работать только с одним типом объекта.

на переходник будет тогда реализуйте цель интерфейс делегирует свои вызовы метода Adaptees, переданные переходник через конструктор.

чтобы вы поняли это в коде Java, я написал очень простой проект, используя точно такой же пример, упомянутый выше, используя адаптеры для работы с несколькими интерфейсами smart TV. Код небольшой, хорошо документированный и понятный, поэтому копайте на нем, чтобы увидеть, как будет выглядеть реализация в реальном мире как.

просто загрузите код и импортируйте его в Eclipse (или вашу любимую IDE) в качестве проекта Maven. Вы можете выполнить код, запустив org.образец.Главный.java. Помните, что здесь важно понять, как классы и интерфейсы собираются вместе для разработки шаблона. Я также создал некоторые поддельные Adaptees в пакете com.третья часть.libs. Надеюсь на это. помогает!

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


используйте адаптер, когда у вас есть интерфейс, который вы не можете изменить, но который вам нужно использовать. Смотрите на это, как на новичка в офисе, и вы не можете заставить седых следовать вашим правилам - вы должны адаптироваться к их. Вот реальный пример из реального проекта, над которым я когда-то работал, где пользовательский интерфейс дан.

У вас есть приложение, которое считывает все строки в файле в структуру данных списка и отображает их в сетке (давайте вызовем базовый интерфейс хранилища данных IDataStore). Пользователь может перемещаться по этим данным, нажимая кнопки "первая страница", "Предыдущая страница", "Следующая страница", "последняя страница". Все работает нормально.

теперь приложение должно использоваться с производственными журналами, которые слишком велики для чтения в память, но пользователю все равно нужно перемещаться по нему! Одним из решений было бы реализовать кэш, который хранит первую страницу, следующую, предыдущую и последнюю страницы. Что мы хотим, когда пользователь нажимает "Следующая страница", мы возвращаем страницу из кэш и обновить кэш; когда они нажимают последнюю страницу, мы возвращаем последнюю страницу из кэша. На заднем плане у нас есть filestream делает все волшебство. Таким образом, у нас есть только четыре страницы в памяти, а не весь файл.

вы можете использовать адаптер для добавления этой новой функции кэша в приложение без уведомления Пользователя. Мы расширяем текущее IDataStore и называем его CacheDataStore. Если файл для загрузки большой, мы используем CacheDataStore. Когда мы делаем запрос для первого, Следующая, предыдущая и последняя страницы, информация направляется в наш кэш.

и кто знает, завтра Босс хочет начать читать файлы из таблицы базы данных. Все, что вы делаете, это по-прежнему расширять IDataStore в SQLDataStore, как и для кэша, настроить соединение в фоновом режиме. Когда они нажимают кнопку Далее, вы создаете необходимый sql-запрос, чтобы получить следующие пару сотен строк из базы данных.

по существу, оригинальный интерфейс приложения не изменение. Мы просто адаптировали современные и интересные функции для работы с ним, сохранив устаревший интерфейс.


пример@Justice o не говорит о шаблоне адаптера четко. Расширение его ответа - У нас есть существующий интерфейс IDataStore, который использует наш потребительский код, и мы не можем его изменить. Теперь нас просят использовать классный новый класс из библиотеки XYZ, который делает то, что мы хотим реализовать, но, но, мы не можем изменить этот класс, чтобы расширить наш IDataStore, уже видели проблему ? Создание нового класса-адаптера, реализующего интерфейс, который ожидает наш потребительский код, т. е. IDataStore и используя класс из библиотеки, функции которой нам нужно иметь-адаптировать, как член нашего адаптера, мы можем достичь того, чего хотели.


Это пример реализации адаптера:

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