简体   繁体   中英

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.".
    }
}

In this example, I have two servers. Unfortunately, one server uses XML , and the other uses JSON . They both have to communicate with each other. So I made an adapter that implements the Server interface and contains the two servers. I want whenever the ServerThatUsesXML sends something to the adapter, the adapter converts it to JSON and forward it to the ServerThatUsesJSON . And the same holds for converting JSON requests to XML requests.

The problem is that since the two servers implement the same interface, both servers has the same methods with the same signature. So when I call accept for example on the Adapter , the Adapter won't know where did the request come from and which way the request should go. Should I pass it to the JSON server? or should I pass it to the XML server?

I have two solutions but they don't look so clean... So I'm asking whether there is a better approach to solve this problem.

First solution: to check the format of the text. If it's an XML text, convert it to JSON and send it to the ServerThatUsesJSON . The same holds for the requests converting from JSON to XML . This approach is probably the worst, since it doesn't check the sender and forwards the requests only based on the format of the text. Also it goes through the text to check the format. This is not so efficient.

Second solution: to make two adapters, one that accepts XML and sends JSON , and another one that accepts JSON and sends XML . And then pass the first one to the ServerThatUsesXML . And pass the second one to the ServerThatUsesJSON . This solution looks better that the first one (at least it's more efficient).

My question is: can I make two accept functions for example accpetXML and acceptJSON and in the accept function, depending on the type of the caller, I either call the XML version or the JSON version. The code should look something like this:

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

The GoF mentions "two-way adapters" on page 143.

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

With the Server interface, however, different clients view it in exactly the same way. There is only one interface to adapt rather than two, so this is a clue that a two-way adapter may not be suitable.

The example from the GoF shows a two-way class adapter using multiple inheritance.

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.

Clearly this tells us that a two-way class adapter is not suitable to the Server use case. I think it may be sufficient evidence to conclude that adapting two classes with the same interface is not a viable use for two-way adapters at all. While the GoF does not mention a two-way object adapter (using composition rather than multiple inheritance) it would seem to encounter the same problem of different input formats to one API.

Incidentally, the problem with different String formats is more an effect of Stringly Typed programming. It can be solved by programming with objects instead of primitives. If the servers would deserialize their inputs, the problem vanishes. This is a surprisingly common problem: servers have type information (because they know what format to accept) but they throw that information away by passing serialized data (such as a String) to another object that has to deal with different formats.

Returning to the topic of the Adapter pattern, you might implement different (one-way) adapters: one specifically for the XML server that converts to JSON and another specifically for the JSON server that converts to XML. This solution is similar to the comments of passing the Converter into each Server and making the String format the Server s' problem, which is essentially the same deserialization solution that avoids propagating Strings.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM