Вопрос по design-patterns, oop, adapter, software-design – адаптер-любой реальный пример шаблона адаптера

71

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

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

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

Хорошо, если вы хотите продемонстрировать это. У вас должен быть готовый пример этого в вашей среде, фактически несколько. В противном случае, почему вы хотите продемонстрировать это? Tony Hopkinson
@TonyHopkinson Я, возможно, использовал здесь неправильный термин продемонстрировать, но я имел в виду, чтобы объяснить концепцию этого шаблона хорошим примером. Я согласен, я должен найти тот в моей собственной системе ... AksharRoop
@AksharRoop. Шаблон проектирования предназначен для решения проблемы, а не для решения проблемы. Лучший пример - один в вашем собственном "мире". Tony Hopkinson
Несколько примеров здесь.stackoverflow.com/questions/1673841/… r4.
@TonyHopkinson Цель состоит в том, чтобы люди знали об этом шаблоне проектирования с реальным примером. AksharRoop

Ваш Ответ

13   ответов
7

Adapter pattern works as a bridge between two incompatible interfaces. This pattern involves a single class called adapter which is responsible for communication between two independent or incompatible interfaces.

В качестве примера можно привести переводчик языка или мобильное зарядное устройство. Больше здесь в этом видео на YouTube:

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

2

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

Вы можете использовать шаблон проектирования адаптера, когда вам приходится иметь дело с различными интерфейсами с похожим поведением (что обычно означает классы с похожим поведением, но с разными методами). Примером этого может быть класс для подключения к телевизору Samsung, а другой - для подключения к телевизору Sony. Они будут иметь общее поведение, такое как открытое меню, запуск воспроизведения, подключение к сети и т. Д., Но каждая библиотека будет иметь свою реализацию (с разными именами методов и сигнатурами). Эти различные реализации конкретного поставщика называютсяAdaptee в диаграммах UML.

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

Adapters затем будет осуществлятьTarget интерфейс, делегирующий свои вызовы методовAdaptees которые передаютсяAdapters через конструктор.

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

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

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

1

Настоящим примером может служить отчет о документах в приложении. Простой код, как здесь.

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

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
Это на самом деле прокси. Адаптер и адаптер имеют разные интерфейсы. Они не реализуют один и тот же интерфейс. Это то, что делает прокси.
0

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

0

Согласно & # x201C; C # 3.0 Шаблоны проектирования & # x201D; В книге Джудит Бишоп Apple использовала шаблон Adapter для адаптации Mac OS для работы с продуктами Intel (объяснение в главе 4, выдержка здесь2)

41

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

 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));
Я француз, и я чувствую оскорбление & # xE9; что вы не считаете меня настоящим человеком. (Дж)
@ ZeroUltimax Я уверен, что этот код не скомпилируется в Квебеке.
Что если вы не управляете интерфейсом и вам необходимо адаптировать один из ваших классов к сторонней библиотеке? Множество других веских причин, которые выходят за рамки этого ответа.
Любой кодер, не имеющий знаний об адаптерах, легко решил бы проблему. Как знание теории адаптеров помогает сэкономить время или улучшить решение? Является ли конечной целью использование специального класса вместо использования только метода?
0

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

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

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

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

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

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

@berimbolo Ваша путаница действительна, так как приведенный выше пример не говорит о шаблоне адаптера.
Я не понимаю? Похоже, вы просто использовали существующий интерфейс и реализовали методы? Где другой интерфейс, к которому нужно адаптироваться, и класс адаптера?
-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);
}
11

Вот пример, который имитирует преобразованиеanalog data вdigit data.

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


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 - Test case

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

Dependence - via 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>

How to test

Просто запустите юнит-тест.

2

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

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

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

42

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

Any real example of Adapter Pattern

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

enter image description here

71

Многие примеры Адаптера тривиальны или нереальны (Rectangle vs. LegacyRectangle, Ratchet vs. Socket, SquarePeg против RoundPeg, Утка против индейки). Хуже того, многие не показываютmultiple Adapters for different Adaptees (кто-то привел в качестве примера шаблона адаптера Java Arrays.asList). Адаптация интерфейсаonly one class работа с другим кажется слабым примером шаблона адаптера GoF. Этот шаблон использует наследование и полиморфизм, поэтому можно ожидать, что хороший пример покажетmultiple implementations of adapters for different adaptees.

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

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

Fig. 26.1

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

Fig. 26.2

и, конечно же, реализация в PHP:github.com/alex-moreno/DesignPatternsPHP/tree/master/Adapter
этот пример использования сессий тоже довольно хорош (хотя реализация, я думаю, не совсем правильная, с использованием статики):community.sitepoint.com/t/phpunit-testing-cookies-and-sessions/…

Похожие вопросы