The Adapter pattern (also known as a "Wrapper") is a structural design pattern that allows objects with incompatible interfaces to collaborate. It acts as a translator between two different interfaces, wrapping an existing class with a new interface to make it compatible with a client's expectations.
In software development, we often need to use third-party libraries or legacy code that we cannot modify. If their method signatures or data requirements do not match our modern system's architecture, we face an incompatibility gap.
Scenario: We are developing a modern Graphic Design application.
-
The Target Interface (ModernRectangle): Our system expects to draw rectangles by providing two points the Top-Left corner
(x1, y1)and the Bottom-Right corner(x2, y2). -
The Adaptee (LegacyRectangle): We have a powerful legacy library, but it uses a different coordinate system. It requires the Top-Left corner
(x, y), followed by the Width and the Height of the rectangle.
Instead of changing our modern code or hacking the legacy library, we
introduce the 'RectangleAdapter'.
This adapter implements our 'Modern' interface but internally holds an
instance of the 'Legacy' class. When our system calls draw(x1, y1, x2, y2),
the adapter performs the necessary mathematical translation:
- width = x2 - x1
- height = y2 - y1
Then, it redirects the call to the legacy method:
- legacy->oldDraw(x1, y1, width, height).
- Reusability: We can use the legacy library without modifying its source code.
- Decoupling: The client (our app) remains independent of the legacy library's specific implementation details.
- Single Responsibility: The conversion logic is centralized in one place.