Как сделать двунаправленный адаптер для двух классов, реализующих один и тот же интерфейс? - PullRequest
1 голос
/ 06 мая 2020
interface Server
{
    void accept(String xml);
    void send();
}

class ServerThatUsesXML implements Server
{
    Server server;

    @Override
    public void accept(String xml) {
        if (xml.equals("XML"))
            System.out.println("Data accepted successfully.");
        else
            System.out.println("There was a problem in processing the data.");
    }

    @Override
    public void send() {
        server.accept("XML");
    }
}

class ServerThatUsesJSON implements Server
{
    Server server;

    @Override
    public void accept(String json) {
        if (json.equals("JSON"))
            System.out.println("Data accepted successfully.");
        else
            System.out.println("There was a problem in processing the data.");
    }

    @Override
    public void send() {
        server.accept("JSON");
    }
}

class Converter
{
    public String convertToXML(String json)
    {
        return "XML";
    }

    public String convertToJSON(String xml)
    {
        return "JSON";
    }
}

class Adapter implements Server
{
    Server xml, json;
    Converter converter = new Converter();

    public Adapter(Server xml, Server json) {
        this.xml = xml;
        this.json = json;
    }

    @Override
    public void accept(String input) {
        // converter.convertTo...
    }

    @Override
    public void send() {
        // converter.convertTo...
    }
}

public class Main {

    public static void main(String[] args) {
        ServerThatUsesXML xml = new ServerThatUsesXML();
        ServerThatUsesJSON json = new ServerThatUsesJSON();

        xml.server = json;
        json.server = xml;

        xml.send(); // There was a problem in processing the data.
        json.send(); // There was a problem in processing the data.

        Adapter adapter = new Adapter(xml, json);
        xml.server = adapter;
        json.server = adapter;

        xml.send();
        json.send();
        // Both calls should print "Data accepted successfully.".
    }
}

В этом примере у меня два сервера. К сожалению, один сервер использует XML, а другой - JSON. Им обоим нужно общаться друг с другом. Итак, я сделал адаптер, реализующий интерфейс Server и содержащий два сервера. Я хочу, чтобы каждый раз, когда ServerThatUsesXML отправляет что-то в адаптер, адаптер конвертирует это в JSON и пересылает на ServerThatUsesJSON. То же самое касается преобразования JSON запросов в XML запросов.

Проблема в том, что, поскольку два сервера реализуют один и тот же интерфейс, оба сервера имеют одинаковые методы с одинаковым назначением. Поэтому, когда я вызываю accept, например, на Aapter, Adapter не будет знать, откуда пришел запрос и каким образом он должен go. Следует передать его на сервер JSON? или я должен передать его на сервер XML?

У меня есть два решения, но они не выглядят такими чистыми ... Поэтому я спрашиваю, есть ли лучший подход для решения этой проблемы.

Решение первое: проверить формат текста. Если это текст XML, преобразуйте его в JSON и отправьте в ServerThatUsesJSON. То же самое и для запросов, конвертируемых из JSON в XML. Этот подход, вероятно, наихудший, поскольку он не проверяет отправителя и пересылает запросы только на основе формата текста. Также он просматривает текст, чтобы проверить формат. Это не так эффективно.

Второе решение: сделать два адаптера, один, который принимает XML и отправляет JSON, а другой, который принимает JSON и отправляет XML. А затем передайте первый в ServerThatUsesXML. А второй передайте в ServerThatUsesJSON. Это решение выглядит лучше первого (по крайней мере, более эффективно).

Мой вопрос: могу ли я сделать две функции accept, например accpetXML и acceptJSON, а в функции accept, в зависимости от типа вызывающего абонента, я либо вызываю XML версия или версия JSON. Код должен выглядеть примерно так:

public void accept(String input, ....)
{
    if (senderType == ServerThatUsesXML)
        acceptJSON(converter.convertToJSON(input));
    else
        acceptXML(converter.convertToXML(input));
}

1 Ответ

2 голосов
/ 07 мая 2020

GoF упоминает «двусторонние адаптеры» на странице 143.

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

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

Пример из GoF показывает двусторонний адаптер класса, использующий множественное наследование.

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

Очевидно, это говорит нам, что двусторонний адаптер класса не подходит для варианта использования Server . Я думаю, это может быть достаточным доказательством, чтобы сделать вывод о том, что адаптация двух классов с одним и тем же интерфейсом вообще нецелесообразна для двусторонних адаптеров. Хотя в GoF не упоминается двусторонний адаптер объект (с использованием композиции, а не множественного наследования), похоже, что возникает та же проблема, связанная с разными форматами ввода для одного API.

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

Возвращаясь к вершине c шаблона адаптера, вы можете реализовать разные (односторонние) адаптеры: один специально для сервера XML, который преобразуется в JSON, а другой специально для сервера JSON, который преобразуется в XML. Это решение аналогично комментариям о передаче Converter в каждый Server и превращении формата String в проблему Server s, что по сути является тем же решением десериализации, которое позволяет избежать распространения строк.

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