What is the Adapter standard?

15

What is and how the Adapter pattern works in Java, I am trying to understand this pattern because I will use the same in a project.

    
asked by anonymous 10.09.2015 / 02:43

1 answer

16

In short, the Adapter project standard is to adapt the interface of a class or object to be used differently, but without changing the interface or implementation.

Example: persistence in different services

A common case is when we've developed a client code that wants to use several heterogeneous sources.

For example, you have several implementations that can read and write files from multiple services:

class DropBox {
    void upload(DropBoxFile dbFile) {}
    DropBoxFile download(String id) {} 
}

class AWS {
    void save(InputStream input, int id) {}
    InputStream restore(int id) {} 
}

class GoogleDrive {
    void send(byte[] data, String name) {}
    byte[] get(String name) {} 
}

Each of these classes is in a different library or project. You do not want to make changes or duplicate the code.

Now imagine that you have a system where the user can decide in which service the data will be saved. One way is to write a procedural code full of if s and else s each time the system needs to use one of the available services, eg:

if (dropbox) {
  //faz alguma coisa
} else if (aws) {
 //faz outra
} else if (drive) {
 // outra ainda
}

But you will not want this multiple times on the system, plus the code needed to convert the system types to the specific types of services. Think about how much maintenance it would take to add a new service

So we can define a persistence interface:

interface Persistencia {
    void gravar(File file);
    File ler(String id);
}

The entire system would be implemented using only this interface. A marvel from the point of view of Object Guidance, without if s, no need to change the code if any service changes.

But the problem is not completely solved. The service classes that we do not want to change do not implement our interface.

So, for each service, we must implement an adapter. For example:

class DropBoxAdapter implements Persistencia {
  DropBox dropBox;
  DropBoxAdapter(DropBox dropBox) {
    this.dropBox = dropBox;
  }
  void gravar(File file) {
    dropBox.upload(new DropBoxFile(file.getAbsolutePath());
  }
  File ler(String id) {
    DropBoxFile dbFile = dropBox.download(id);
    return new File(dbFile.getLocalPath());
  }
}

Note that we have just created a class that allows us to use a DropBox object using the Persistencia interface. We adapt the original class according to the desired interface.

Other implementations of adapters should then be provided to other services using the same principle.

Example: improving legacy code

Now imagine that we have to maintain a poorly designed system that implements logs manually using the following class:

class HomeMadeLog {
    public void log(int nivel, String mensagem, Throwable erro) {
        String s = formatarLog(nivel, mensagem, erro);
        adicionaLogNoArquivo(s);
    }
    private String formatarLog(...) { }
    private String adicionaLogNoArquivo(...) { }
}

We need to modernize the logs using a framework like Log4j, but there are thousands of calls to the old method, and many of them are too complicated to simply do an automatic replacement.

In addition, we want to avoid generating 99% of the project files, as this would generate a major conflict problem in the version control system for all other developers.

One solution is to extend the HomeMadeLog class so that it is an adapter for Log4j. Example:

class HomeMadeLogToLog4jAdaptor extends HomeMadeLog {
    Logger logger = Logger.getLogger();
    @Override
    public void log(int nivel, String mensagem, Throwable erro) {
        if (nivel == 0) logger.debug(mensagem, erro);
        else if (nivel == 1) logger.info(mensagem, erro);
        else if (nivel == 2) logger.error(mensagem, erro);
    }
}

Now just provide an instance of HomeMadeLogToLog4jAdaptor instead of HomeMadeLog and all classes will start working with Log4j without modifications.

Considerations

Note that the main asset of the Adapter project standard is to enable code reuse consistently while maintaining compatibility with other libraries and earlier versions of code.

An adapter class is nothing more than a class that implements the interface you want to use and delegates the actual execution to a third class that has the implementation we want to use.

Also note that my examples are purposefully simplified. Some details and complexities that are not related to the pattern itself have been omitted so as not to complicate the examples.

    
10.09.2015 / 08:53