Adaptor Pattern
Photo by Hayley Maxwell on Unsplash

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:

  1. You want to use an existing class, but its interface is not compatible with the rest of your code.
  2. You want to create a reusable library that works with classes having incompatible interfaces.
  3. You want to decouple code so that changes in one class don’t affect other classes.

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

  • Promotes Reusability: Allows the use of existing classes without modifying them.
  • Decouples Code: Maintains compatibility with the existing system, reducing tight coupling.
  • Flexibility: New types can be integrated easily without major changes to the existing code.

Cons

  • Increased Complexity: Adds an extra layer of abstraction, which can make the code more complex.
  • Performance Overhead: Can introduce slight performance overhead due to additional method calls.
  • Understanding Required: Requires understanding of both the target and adaptee interfaces to implement correctly.

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

要查看或添加评论,请登录

Chirag Vaswani的更多文章

  • Iterator Pattern

    Iterator Pattern

    WHAT IS ITERATOR PATTERN? Iterator pattern allows us to traverse elements of a collection without exposing its…

  • Command Pattern

    Command Pattern

    The Command design pattern encapsulates a request as an object, thereby allowing users to parameterize clients with…

  • Chain of Responsibility Pattern

    Chain of Responsibility Pattern

    Ever faced challenges managing complex workflows with multiple handlers in a serial manner? CoR to the rescue… THE WHAT…

  • Proxy Pattern

    Proxy Pattern

    Ever wondered how you can manage heavy resources in your applications without slowing down performance? There is way to…

  • Flyweight Pattern

    Flyweight Pattern

    Flyweight is a class in boxing which includes fighters weighing up to and including 51 kg (112 lb) for a title fight…

  • Facade Pattern

    Facade Pattern

    The What The Facade Pattern is a structural design pattern that provides a simplified interface to a complex subsystem,…

  • Decorator Pattern

    Decorator Pattern

    The Decorator Pattern is a structural design pattern that allows you to dynamically attach additional responsibilities…

  • Composite Pattern

    Composite Pattern

    Have you ever struggled with managing complex hierarchical structures in your code? Composite pattern can simplify your…

  • Bridge Pattern

    Bridge Pattern

    Ever felt overwhelmed by the explosion of subclasses when trying to support multiple variations in your code? What if…

  • Singleton Pattern: A Comprehensive Guide

    Singleton Pattern: A Comprehensive Guide

    The Singleton Pattern is one of the most widely used design patterns in software engineering. Whether you are working…

社区洞察

其他会员也浏览了