From "Design Patterns"
🎧 Listen to Summary
Free 10-min PreviewThe Adapter Pattern
Key Insight
The Adapter pattern enables classes with incompatible interfaces to work together by converting one interface into another that clients expect. Its core motivation is to reuse existing classes, especially from toolkits, without modifying their source code or forcing them to adopt domain-specific interfaces. For instance, a drawing editor expecting graphical objects through a 'Shape' interface might need to incorporate an existing 'TextView' class, designed for displaying and editing text with a different interface. An adapter, like 'TextShape', bridges this incompatibility, enabling the 'TextView' functionality to be used within the 'Shape' hierarchy. This pattern is applicable when an existing class's interface does not match the required one, or when creating reusable components that must cooperate with unforeseen classes with diverse interfaces.
Adapters can be implemented as either class adapters or object adapters, each with distinct characteristics. A class adapter utilizes multiple inheritance, inheriting the target interface publicly and the adaptee implementation privately. This approach lets the adapter override adaptee behavior and involves a single object, but it binds to a specific concrete adaptee class and cannot adapt an adaptee and all its subclasses simultaneously. Conversely, an object adapter relies on object composition, maintaining a reference to an adaptee instance and forwarding client requests to it. This method offers greater flexibility, allowing one adapter to work with multiple adaptees, including subclasses, and to add functionality not present in the original adaptee, such as a 'TextShape' implementing a 'CreateManipulator' operation that 'TextView' lacks.
The degree of adaptation varies, from simple operation renaming to supporting entirely different sets of operations, depending on interface similarity. Pluggable adapters are a powerful variant, building interface adaptation directly into reusable classes, thereby minimizing assumptions about client interfaces. For example, a 'TreeDisplay' widget can display diverse hierarchical structures (like directory or inheritance hierarchies) by adapting their specific child-access operations, such as 'GetSubdirectories' or 'GetSubclasses', using techniques like abstract operations, delegate objects, or parameterized blocks. Furthermore, two-way adapters exist, providing transparency by conforming to both the target and adaptee interfaces, enabling an object to be viewed differently by various clients, as seen in systems integrating 'StateVariable' and 'ConstraintVariable' classes.
📚 Continue Your Learning Journey — No Payment Required
Access the complete Design Patterns summary with audio narration, key takeaways, and actionable insights from Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides.