Adapter Design Pattern Example

Adapter Design Pattern:  The adapter design pattern is a design pattern that translates one interface for a class into a compatible interface.

Adapter converts the interface of a class into another interface which is required or expect by clients. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.

Adapter also known as wrapper, an alternative naming shared with the Decorator pattern according to the GoF Design Patterns book.

Situations: During application development some time we face the following situations 

  • Sometimes a toolkit or class library can not be used because its interface is incompatible with the interface required by an application. 
  • We can not change the library interface, since we may not have its source code. 
  • Even if we did have the source code, we probably should not change the library for each domain-specific application.

When to use: The Adapter pattern can be used when

  • You want to use an existing class, and its interface does not match the one you need
  • You want to create a reusable class that cooperates with unrelated classes with incompatible interfaces
Implementation Issues: How much adapting should be done?
  • Simple interface conversion that just changes operation names and order of arguments
  • Totally different set of operations
This question has a really simple response: it should do how much it has to in order to adapt. It's very simple, if the Target and Adaptee are similar then the adapter has just to delegate the requests from the Target to the Adaptee. If Target and Adaptee are not similar, then the adapter might have to convert the data structures between those and to implement the operations required by the Target but not implemented by the Adaptee.

Does the adapter provide two-way transparency?
  • A two-way adapter supports both the Target and the Adaptee interface. It allows an adapted object (Adapter) to appear as an Adaptee object or a Target object.
The Two-Ways Adapters are adapters that implements both interfaces of Target and Adaptee. The adapted object can be used as Target in new systems dealing with Target classes or as Adaptee in other systems dealing with Adaptee classes. Going further on this line of thinking, we can have adapters implementing n interfaces, adapting to n systems. Two-way adapters and n-way adapters are hard to implement in systems not supporting multiple inheritance. If adapter has to extend the Target class it can not extent another class like Adaptee, so the Adaptee should be an interface and all the calls should be delegated from the adapter to the Adaptee object.

Lets under stand the Adapter pattern using a simple example. Suppose we have developed an application in which we are reading text files and displaying the content. So to read the file content we are using some LegacyFileReader class which is using a native call as following.
LegacyFileReader .java
public class LegacyFileReader {
    public static void native String[] readLinesFromFile(String file);
       
          String[] readLines(String file) {
                 return   readLinesFromFile(file); // native code is used to read file content
         }
}

or even it could be such code which is not giving good performance or it is not well written code.
Now suppose a new Library came which is giving good performance and has well written code.
Now the Architect has  decided to use this new library in the Application in place of LegacyFileReader.
So in order to drop this LegacyFileReader and use the new Library we need to look the File Reader class from the library. The new library jar contains the file reader as ThirdPartyFileReader.class.

ThirdPartyFileReader.class may look like following

public class ThirdPartyFileReader extends FileInputStream {
                private String file;

                public ThirdPartyFileReader(String file) throws FileNotFoundException {
                                super(file);
                                this.file = file;
                }

                /**
                 * Read the given file and return all data as byte array
                 */
                public byte[] readFile() {
                             byte[] result = new byte[(int) new File(file).length()];
                             try {
                                int totalBytesRead = 0;
                                while (totalBytesRead < result.length) {
                                            int bytesRemaining = result.length - totalBytesRead;
                                            int bytesRead = read(result, totalBytesRead, bytesRemaining);
                                                if (bytesRead > 0) {
                                                                totalBytesRead = totalBytesRead + bytesRead;
                                                }
                                }
                                } catch (Exception ex) {
                                                ex.printStackTrace();
                                }
                                return result;
                }
}

Problem: Here you can see readFile() method returns byte array which is not the same as Legacy class method readLines(file) return type. So to make it compatible or same method either we need to modify the third party class which is not permitted in any case since its third party class, not yours and you don't own source code also. since this is a class file so only public methods will be visible to you, You don't know how the methods are implemented in the third party class...


No comments :

Post a Comment