如何为实现相同接口的两个 类 创建双向适配器?

How to make bidirectional adapter for two classes that implement the same interface?

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 请求也是如此。

问题在于,由于两台服务器实现了相同的接口,因此两台服务器具有相同的方法和相同的签名。因此,例如,当我在 Adapter 上调用 accept 时,Adapter 将不知道请求来自何处以及请求应采用哪种方式。我应该将它传递给 JSON 服务器吗?还是我应该将它传递给 XML 服务器?

我有两个解决方案,但它们看起来不太干净...所以我想问一下是否有更好的方法来解决这个问题。

第一个解决方案:检查文本的格式。如果是 XML 文本,将其转换为 JSON 并将其发送到 ServerThatUsesJSON。从 JSON 转换为 XML 的请求也是如此。这种方法可能是最糟糕的,因为它不检查发件人并仅根据文本格式转发请求。它还通过文本检查格式。这样效率不高。

第二种解决方案:制作两个适配器,一个接受XML并发送JSON,另一个接受JSON并发送XML。然后将第一个传递给ServerThatUsesXML。并将第二个传递给 ServerThatUsesJSON。这个解决方案看起来比第一个更好(至少它更有效)。

我的问题是:我可以创建两个 accept 函数,例如 accpetXMLacceptJSON 并在 accept 函数中,具体取决于调用者的类型,我要么调用 XML 版本,要么调用 JSON 版本。代码应如下所示:

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

GoF 在第 143 页提到 "two-way adapters"。

Specifically, they're useful when two different clients need to view an object differently.

然而,对于Server界面,不同的客户端以完全相同的方式查看它。只有一个接口可以适配而不是两个,所以这是双向适配器可能不适合的线索。

GoF 中的示例显示了使用多重继承的双向 class 适配器。

Multiple inheritance is a viable solution in this case because the interfaces of the adapted classes are substantially different. The two-way class adapter conforms to both of the adapted classes and can work in either system.

很明显,这告诉我们双向 class 适配器不适合 Server 用例。我认为有足够的证据可以得出这样的结论:用相同的接口适配两个 classes 根本不是双向适配器的可行用途。虽然 GoF 没有提到双向 object 适配器(使用组合而不是多重继承),但它似乎遇到了一个 API 的不同输入格式的相同问题。

顺便说一句,不同字符串格式的问题更多是Stringly Typed 编程的影响。它可以通过使用对象而不是原语编程来解决。如果服务器反序列化它们的输入,问题就消失了。这是一个令人惊讶的常见问题:服务器有类型信息(因为它们知道接受什么格式)但是它们通过将序列化数据(例如字符串)传递给必须处理不同格式的另一个对象来丢弃该信息。

回到适配器模式的主题,您可以实现不同的(单向)适配器:一个专门用于转换为 JSON 的 XML 服务器,另一个专门用于 JSON 转换为 XML 的服务器。此解决方案类似于将 Converter 传递给每个 Server 并使 String 格式成为 Server 的问题的注释,这与避免传播字符串的反序列化解决方案本质上相同。