Adapter Design Pattern in Python
This story is part of the “Design Patterns” series. You can find the other stories of this series here:
You can also find all the code used through this series on GitHub.
The Adapter design pattern is a structural pattern that allows two incompatible interfaces to work together.
This is done by creating a wrapper class that converts the interface of one class into that of the other.
Problems the Adapter can Solve
For example, let’s say you have a class called Rectangle that represents a rectangle and has a width and height property. You also have a class called Square that represents a square and has a sideLength property.
To make the Square and Rectangle classes work together without using an Adapter, you might create a new class called SquareRectangle that extends the Rectangle class and adds a side_length property. The SquareRectangle class would look like this:
class SquareRectangle(Rectangle):
def __init__(self, side_length):
super().__init__(side_length, side_length)
self.side_length = side_lengthTo use the SquareRectangle class, you would do the following:
square_rectangle = SquareRectangle(5)
print(square_rectangle.width) # Output: 5
print(square_rectangle.height) # Output: 5This approach has several disadvantages. First, it requires you to change the existing Rectangle class by creating a new subclass. This makes your code more complex and harder to maintain, because you now have two classes that do the same thing, but in slightly different ways.
Second, it means that you can no longer use the Square class on its own, because it does not have the width and height properties that are required to work with the Rectangle class. This makes your code less flexible and more difficult to work with.
Solution
By using an Adapter, you can avoid these problems and make the Square and Rectangle classes work together without changing either of the existing classes. This makes your code simpler, more maintainable, and more flexible.
There are many implementations of the Adapter pattern. Sometimes you can make the Adapter class inherit the classes to adapt, sometimes not, it depends.
Here is an implementation without using inheritance:
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def get_area(self):
return self.width * self.height
class Square:
def __init__(self, side_length):
self.side_length = side_length
def get_area(self):
return self.side_length ** 2
class SquareToRectangleAdapter:
def __init__(self, square):
self.square = square
@property
def width(self):
return self.square.side_length
@property
def height(self):
return self.square.side_length
def get_area(self):
return self.square.get_area()
# Now we can use the SquareToRectangleAdapter class to use the Square class
# as if it were a Rectangle
square = Square(4)
adapter = SquareToRectangleAdapter(square)
print(adapter.width) # 4
print(adapter.height) # 4
print(adapter.get_area()) # 16The SquareToRectangleAdapter class allows us to use the Square class as if it were a Rectangle by providing width and height properties that return the side length of the square. This allows us to use the get_area method of the Rectangle class to compute the area of the square.
Applicability
It can be useful when you have an existing class that provides certain functionality, but you want to use it in a context where a different interface is expected.
For example, if you have a class that provides a list-like interface for storing and accessing data, but you want to use it in a context where a dictionary-like interface is expected, you could use the Adapter pattern to create a new class that adapts the list-like class to provide the dictionary-like interface.
Advantages
- It allows you to integrate existing code and libraries with different interfaces into a new system without having to modify the original code.
- It makes it easier to use existing code and libraries in different contexts, since you can create adapters that adapt their interfaces to match the requirements of the new context.
- It can make your code more flexible and reusable, since you can create adapters for different interfaces and use them in multiple contexts.
Disadvantages
- It can add complexity to your code, since you need to create and maintain additional adapter classes.
- It can make your code more difficult to understand, since the relationships between the original classes and the adapter classes may not be immediately obvious.
- It can make debugging more difficult, since errors may not be immediately traceable to the source of the problem.
Final Note
Overall, the Adapter pattern can be a useful tool in Python when you need to integrate existing code or libraries with different interfaces into a new system. However, it is important to carefully consider whether the benefits of using the pattern outweigh the potential disadvantages in a given situation.
To explore the other stories of this story, click below!
To explore more of my Python stories, click here! You can also access all my content by checking this page.
If you want to be notified every time I publish a new story, subscribe to me via email by clicking here!
If you’re not subscribed to medium yet and wish to support me or get access to all my stories, you can use my link:
