What is the Adapter standard?

Asked

Viewed 2,610 times

17

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

  • 9

    It’s weird that you want to wear something you don’t understand. Patterns aren’t meant for you to choose and use. They were made to use when there is a need. And to know if you have the need you need to understand it.

  • 5

    Perhaps the standard is quoted in the architecture document, it is common when a system or part of it is designed at a high level and the implementation is delegated to another team.

  • 2

    It’s college project, teacher’s requirement @bigown

  • 2

    Making a basic cramp in Stackoverlow. Kidding :)

  • @Wallacemaxters is more or less, more to understand msm, because I have to develop a project in this pattern

1 answer

17


In summary, the design pattern Adapter consists of adapting the interface of a class or object to be used otherwise, but without changing the interface or implementation.

Example: persistence in different services

A common case is when we develop a code client that intends to use several heterogeneous sources.

For example, you have multiple implementations capable of reading and recording files from various 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 on which service the data will be saved. One way out is to write a procedural code full of ifs and elses each time the system needs to use one of the available services, example:

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

But you will not want this several 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

Then we can define a persistence interface:

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

The whole system would be implemented using only this interface. A wonder from the point of view of Object Orientation, without ifs, no need to change the code if any service changes.

But the problem is not completely solved. Service classes that we don’t want to change don’t implement our interface.

So for each service, we should 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 an object DropBox using the interface Persistencia. Us we adapt the original class according to the desired interface.

Other implementations of Adapters should then be provided for 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 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 overwrite.

What’s more, we want to avoid generating 99% change 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 class HomeMadeLog 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 HomeMadeLog and all classes will work with Log4j without modifications.

Considerations

Note that the main trump of the project pattern Adapter is to allow reuse of code consistently while maintaining compatibility with other libraries and earlier versions of code.

A class adaptor 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.

Note also that my examples are purposefully simplified. Some details and complexities that are unrelated to the pattern itself have been omitted to avoid complicating the examples.

  • In the case of the Log4j example, I would necessarily have to replace the Homemadelog class reference with Homemadelogtolog4jadaptor in all classes, correct? Or in this example you are considering that who provides the Homemadelog would be a static constructor and in this case just replace the return by the subclass?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.