Adaptor Pattern
The Adapter Pattern is about creating an intermediary abstraction that translates, or adapts, one interface into another.
THE WHAT
The Adapter Pattern is a structural design pattern that allows incompatible interfaces to work together. It’s like a translator between two different systems that can’t directly communicate.
THE WHEN: The General Problem It Tries to?Solve
Sometimes in software development, you encounter a situation where you need to use an existing class, but its interface doesn’t match the one you need. The Adapter Pattern helps bridge this gap without modifying the existing code.
Example of the General?Problem
We’ll extend the example used from the factory method pattern article. Consider a software system that manages various types of documents. Initially, it supports text documents, spreadsheets, and presentations. Now, we want to add support for images, but the ImageViewer class has a different interface than the existing Document interface. Directly modifying the existing system to accommodate ImageViewer would lead to tight coupling and make the system difficult to maintain and extend. The Adapter Pattern provides a way to integrate ImageViewer without changing the existing code.
Generalising the?When
Use the Adapter Pattern when:
The How
Let’s integrate an ImageViewer into our document viewer system using the Adapter Pattern.
Step 1: Define the Target Interface
First, we define the Document interface, which all document types should implement.
public interface Document {
void open();
void close();
void save();
}
Step 2: Create the Adaptee Class (this is generally a third?party)
Next, we create the ImageViewer class, which has a different interface.
public class ImageViewer {
public void loadImage(String fileName) {
System.out.println("Loading image: " + fileName);
}
public void closeImage() {
System.out.println("Closing image.");
}
}
Step 3: Create the Adapter?Class
We create an adapter class, ImageAdapter, that implements the Document interface and uses an instance of ImageViewer.
We are using composition here
public class ImageAdapter implements Document {
private ImageViewer imageViewer;
private String fileName;
public ImageAdapter(ImageViewer imageViewer, String fileName) {
this.imageViewer = imageViewer;
this.fileName = fileName;
}
@Override
public void open() {
imageViewer.loadImage(fileName);
}
@Override
public void close() {
imageViewer.closeImage();
}
@Override
public void save() {
System.out.println("Save operation is not supported for images.");
}
}
Existing DocumentViewer class
public abstract class DocumentViewer {
// Factory method
public abstract Document createDocument();
public void openDocument() {
Document doc = createDocument();
doc.open();
// additional operations
}
public void closeDocument() {
Document doc = createDocument();
doc.close();
// additional operations
}
public void saveDocument() {
Document doc = createDocument();
doc.save();
// additional operations
}
}
Step 4: Use the Adapter in the?Client
Finally, we create a concrete creator class, ImageDocumentViewer, that uses the adapter to integrate ImageViewer with the existing document viewer system.
public class ImageDocumentViewer extends DocumentViewer {
private String fileName;
public ImageDocumentViewer(String fileName) {
this.fileName = fileName;
}
@Override
public Document createDocument() {
return new ImageAdapter(new ImageViewer(), fileName);
}
}
Driver
Here’s how you can use the DocumentViewerFactory with the new ImageViewer:
public class DocumentViewerFactory {
public static DocumentViewer getDocumentViewer(String type, String fileName) {
switch (type.toLowerCase()) {
case "text":
return new TextDocumentViewer();
case "spreadsheet":
return new SpreadsheetDocumentViewer();
case "presentation":
return new PresentationDocumentViewer();
case "image":
return new ImageDocumentViewer(fileName);
default:
throw new IllegalArgumentException("Unknown document type: " + type);
}
}
}
public class Main {
public static void main(String[] args) {
// Example usage of the factory
DocumentViewer textViewer = DocumentViewerFactory.getDocumentViewer("text", null);
textViewer.openDocument();
textViewer.saveDocument();
textViewer.closeDocument();
DocumentViewer spreadsheetViewer = DocumentViewerFactory.getDocumentViewer("spreadsheet", null);
spreadsheetViewer.openDocument();
spreadsheetViewer.saveDocument();
spreadsheetViewer.closeDocument();
DocumentViewer presentationViewer = DocumentViewerFactory.getDocumentViewer("presentation", null);
presentationViewer.openDocument();
presentationViewer.saveDocument();
presentationViewer.closeDocument();
DocumentViewer imageViewer = DocumentViewerFactory.getDocumentViewer("image", "photo.jpg");
imageViewer.openDocument();
imageViewer.saveDocument();
imageViewer.closeDocument();
}
}
Output
Opening text document.
Saving text document.
Closing text document.
Opening spreadsheet document.
Saving spreadsheet document.
Closing spreadsheet document.
Opening presentation document.
Saving presentation document.
Closing presentation document.
Loading image: photo.jpg
Save operation is not supported for images.
Closing image.
The Pros and?Cons
Pros
Cons
Conclusion
The Adapter Pattern is a powerful tool for integrating incompatible interfaces, promoting code reusability and flexibility. By providing a way to use existing classes with different interfaces, it adheres to key design principles, making it easier to extend and maintain code. However, it’s essential to balance its benefits against the complexity it introduces, ensuring that its use adds value to your project.
Thank you