Поиск…


Шаблон адаптера (PHP)

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

class Experiment {
    private $routine;
    private $tissue;
    function __construct($routine_in, $tissue_in) {
        $this->routine = $routine_in;
        $this->tissue  = $tissue_in;
    }
    function getRoutine() {
        return $this->routine;
    }
    function getTissue() {
        return $this->tissue;
    }
}

class ExperimentAdapter {
    private $experiment;
    function __construct(Experiment $experiment_in) {
        $this->experiment = $experiment_in;
    }
    function getRoutineAndTissue() {
        return $this->experiment->getTissue().' ('. $this->experiment->getRoutine().')';
    }
}

Адаптер (Java)

Предположим, что в вашей текущей кодовой базе существует интерфейс MyLogger например:

interface MyLogger {
    void logMessage(String message);
    void logException(Throwable exception);
}

Допустим, вы создали несколько конкретных реализаций, таких как MyFileLogger и MyConsoleLogger .

Вы решили, что хотите использовать инфраструктуру для управления связью вашего приложения Bluetooth. Эта структура содержит BluetoothManager со следующим конструктором:

class BluetoothManager {
    private FrameworkLogger logger;

    public BluetoothManager(FrameworkLogger logger) {
        this.logger = logger;
    }
}

BluetoothManager также принимает регистратор, и это здорово! Однако он ожидает, что регистратор, интерфейс которого был определен каркасом, и они использовали перегрузку метода вместо того, чтобы именовать свои функции по-разному:

interface FrameworkLogger {
    void log(String message);
    void log(Throwable exception);
}

У вас уже есть куча реализаций MyLogger которые вы хотели бы использовать повторно, но они не соответствуют интерфейсу FrameworkLogger . Именно здесь идет дизайн-шаблон адаптера:

class FrameworkLoggerAdapter implements FrameworkLogger {
    private MyLogger logger;

    public FrameworkLoggerAdapter(MyLogger logger) {
        this.logger = logger;
    }

    @Override
    public void log(String message) {
        this.logger.logMessage(message);
    }

    @Override
    public void log(Throwable exception) {
        this.logger.logException(exception);
    }
}

Определяя класс адаптера, который реализует интерфейс FrameworkLogger и принимает реализацию MyLogger функциональность может отображаться между различными интерфейсами. Теперь можно использовать BluetoothManager со всеми реализациями MyLogger например:

FrameworkLogger fileLogger = new FrameworkLoggerAdapter(new MyFileLogger());
BluetoothManager manager = new BluetoothManager(fileLogger);

FrameworkLogger consoleLogger = new FrameworkLoggerAdapter(new MyConsoleLogger());
BluetoothManager manager2 = new BluetoothManager(consoleLogger);

Пример Java

Большой существующий пример шаблона адаптера можно найти в классах SWT MouseListener и MouseAdapter .

Интерфейс MouseListener выглядит следующим образом:

public interface MouseListener extends SWTEventListener {
    public void mouseDoubleClick(MouseEvent e);
    public void mouseDown(MouseEvent e);
    public void mouseUp(MouseEvent e);
}

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

obj.addMouseListener(new MouseListener() {

    @Override
    public void mouseDoubleClick(MouseEvent e) {
    }

    @Override
    public void mouseDown(MouseEvent e) {
    }

    @Override
    public void mouseUp(MouseEvent e) {
        // Do the things
    }

});

Вместо этого мы можем использовать MouseAdapter:

public abstract class MouseAdapter implements MouseListener {
    public void mouseDoubleClick(MouseEvent e) { }
    public void mouseDown(MouseEvent e) { }
    public void mouseUp(MouseEvent e) { }
}

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

obj.addMouseListener(new MouseAdapter() {

    @Override
    public void mouseUp(MouseEvent e) {
        // Do the things
    }

});

Адаптер (пример UML и пример)

Для того, чтобы использовать шаблон адаптера и ситуацию, когда он может быть применен более мыслимым, здесь приводится небольшой, простой и очень конкретный пример. Здесь не будет кода, просто UML и описание ситуации примера и его проблемы. По общему признанию, содержимое UML написано как Java. (Ну, в тексте подсказки сказано: «Хорошие примеры - это в основном код», я думаю, что шаблоны проектирования достаточно абстрактны, чтобы их можно было вводить по-другому).

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

Представьте, что вы выполняете приятную услугу доставки пиццы. Клиенты могут заказать онлайн на своем сайте, и у вас небольшая система, использующая класс Pizza для представления вашей пиццы и расчета счетов, налоговых отчетов и т. Д. Цена вашей пиццы указана как одно целое, представляющее цену в процентах (в валюте по вашему выбору).

введите описание изображения здесь

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

введите описание изображения здесь

MoneyAmount состоит из двух целых чисел в качестве входных данных: один для суммы (или некоторой случайной валюты) перед запятой, а другой для суммы процента от 0 до 99 после запятой;

введите описание изображения здесь

В связи с тем, что цена вашей Pizza - это целое число, представляющее общую цену в виде процента (> 99), оно несовместимо с IMeal . Это тот момент, когда шаблон адаптера входит в игру: в случае, если потребовалось бы слишком много усилий, чтобы изменить вашу собственную систему или создать новую, и вы должны реализовать несовместимый интерфейс, вы можете применить адаптер patttern.

Существует два способа применения адаптера pattern: class и объектного адаптера.

Оба имеют общий характер: адаптер ( PizzaAdapter ) работает как своего рода переводчик между новым интерфейсом и адаптированным ( Pizza в этом примере). Адаптер реализует новый интерфейс ( IMeal ), а затем либо наследует от Pizza либо конвертирует свою цену с одного целого на два (адаптер класса)

введите описание изображения здесь

или имеет объект типа Pizza как атрибут и преобразует значения этого (адаптер объекта).

введите описание изображения здесь

Применяя шаблон адаптера, вы будете «переводить» между несовместимыми интерфейсами.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow