Python Adapter Design Pattern

1. Definition

The Adapter Design Pattern allows objects with incompatible interfaces to work together. It acts as a bridge between two interfaces, converting one interface into another based on requirement.

2. Problem Statement

Imagine you have a legacy application that returns data in a specific format. Now, you're building a new system that expects data in a different format. Instead of refactoring the old system (which might be risky and time-consuming), you need a solution to make these two systems work together seamlessly.

3. Solution

The Adapter Pattern provides this solution by introducing a class that joins functionalities of independent or incompatible interfaces. The Adapter class will translate calls from the new system to the old system without altering the existing code.

4. Real-World Use Cases

1. Making legacy software compatible with new systems.

2. Adapting data from third-party APIs to fit application-specific needs.

3. Integrating components in software libraries that have different interfaces.

5. Implementation Steps

1. Identify the target interface that the client requires.

2. Create an adapter class that implements the target interface.

3. In the adapter class, reference the interface of the legacy code.

4. Implement the methods of the target interface in the adapter using the legacy code interface.

6. Implementation in Python

# Legacy code: Old system that returns data in XML format
class LegacySystem:
    def get_data_as_xml(self):
        return "<data>Hello from Legacy System</data>"
# Target interface: New system expects data in JSON format
class TargetInterface:
    def get_data_as_json(self):
        pass
# Adapter
class Adapter(TargetInterface):
    def __init__(self, legacy_system):
        self.legacy_system = legacy_system
    def get_data_as_json(self):
        xml_data = self.legacy_system.get_data_as_xml()
        # Convert XML to JSON (simplified for this example)
        json_data = {"data": xml_data.replace("<data>", "").replace("</data>", "")}
        return json_data
# Client Code
legacy = LegacySystem()
adapter = Adapter(legacy)
print(adapter.get_data_as_json())

Output:

{'data': 'Hello from Legacy System'}

Explanation:

1. LegacySystem represents the old system that returns data in XML format.

2. TargetInterface represents the new system interface that expects data in JSON.

3. Adapter implements TargetInterface and converts data from XML (old system) to JSON (new system).

4. In the client code, an instance of LegacySystem is wrapped inside Adapter, enabling it to fetch data in the required JSON format.

7. When to use?

The Adapter Pattern is useful when:

1. You want to use a class that doesn't have the interface you require.

2. You want to create a reusable class that works with classes that don't necessarily have compatible interfaces.

3. You need to use several existing subclasses, but it's impractical to subclass each one to standardize their interfaces.


Comments