【问题标题】:How to make bidirectional adapter for two classes that implement the same interface?如何为实现相同接口的两个类制作双向适配器?
【发布时间】:2020-05-06 00:50:15
【问题描述】:
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 函数,例如 accpetXMLacceptJSONaccept 函数,根据调用者的类型,我可以调用 XML 版本或JSON 版本。代码应如下所示:

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

【问题讨论】:

  • "每当 ServerThatUsesXML 向适配器发送某些内容时,适配器就会将其转换为 JSON 并将其转发给 ServerThatUsesJSON。",这是否意味着您要发送到适配器时要发送到 JSON-服务器?如果你知道目标服务器接受 JSON,你能不只是将数据转换为 JSON 并直接发送吗?
  • 我认为@Lini 的问题是询问您是否可以修改Server 实现以直接使用Converter 并消除Adapter
  • 服务器只是一个需要澄清的例子。我的问题都是关于适配器模式的。我没有遇到某个服务器的问题。长话短说,我在问是否有可能根据函数调用者的类型采取不同的行动。

标签: java design-patterns interface adapter


【解决方案1】:

GoF 在第 143 页提到了“双向适配器”。

特别是,当两个不同的客户端需要以不同的方式查看对象时,它们很有用。

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

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

在这种情况下,多重继承是一个可行的解决方案,因为适应的类的接口有很大的不同。双向类适配器符合两个适配的类,并且可以在任一系统中工作。

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-30
    • 1970-01-01
    • 2021-12-05
    • 1970-01-01
    • 1970-01-01
    • 2014-10-25
    相关资源
    最近更新 更多