10 The Adapter and Façade Design Patterns
This chapter tackles the recurring challenge of working with external or legacy code that you can’t (or don’t want to) modify and presents two design patterns that make such code easier to use: Adapter and Façade. Adapter reconciles incompatible interfaces so existing components can collaborate without changes, while Façade hides the complexity of a subsystem behind a single, higher-level interface. Through Python examples drawn from sports reporting and athletic fund-raising, the chapter demonstrates how each pattern improves design by isolating change, reducing coupling, and simplifying client code.
For Adapter, the chapter begins with a brittle design in which a reporting class both converts data and prints it, tightly coupling it to the details of each source and making extensions costly. Introducing adapter classes (e.g., FootballData, VolleyballData) that implement a common GameData interface and wrap legacy sources decouples conversion from reporting and lets the legacy printing routine operate uniformly. The result encapsulates data transformation (Encapsulate What Varies), enforces single responsibility, and loosens coupling. The generic Adapter model (Target, Adapter, Adaptee) is presented along with an alternative “class adapter” using multiple inheritance; guidance is given on choosing between object adapters (composition, shareable, adapts subclasses) and class adapters (inheritance, can override Adaptee behavior).
For Façade, the chapter contrasts a duplicated, order-sensitive orchestration of multiple components (Alumni, BoosterClubs, Students) with a cleaner design that introduces a FundRaiser façade exposing a single do_fund_raising() method. Clients (AthleticsDept, Administration) no longer depend on the subsystem’s interfaces or call sequence; duplication is removed (DRY), coupling is reduced (Principle of Least Knowledge), and the subsystem becomes easier to extend (e.g., adding CorporateSponsors affects only the façade). The generic Façade model is outlined, and the chapter closes with guidance: use Adapter when you must fit disparate code to a required interface, and use Façade when you want a unified, simpler entry point that hides a complex subsystem.
In the first version of the application, classes BaseballData, FootballInfo, and VolleyballStats present their venue and attendance data in different ways. Therefore, class AttendanceReport has three overloaded public print() methods. But the class’s legacy method legacy_print(), which we cannot change, can only print GameData objects. Therefore, the class has a nested private class _ConvertedData to convert FootballInfo and VolleyballStats objects to GameData objects. BaseballData is already an GameData object.
This version of the application uses the Adapter Design Pattern. Adapter classes FootballData and VolleyballData each implements the GameData interface. Each wraps classes FootballInfo and VolleyballStats, respectively, and encapsulate the data conversion code. The grayed-out portions of the diagram have not changed logically from figure 10.1.
The generic model of the Adapter Design Pattern. Compare with figure 10.2. The Adapter class implements the Target interface. It adapts an Adaptee class by wrapping it so that the latter can work with the Target interface.
In the alternative version of the Adapter Design Pattern, adapter class FootballData implements the GameData interface and inherits from (rather than aggregates) the FootballInfo class. Adapter class VolleyballData implements the GameData interface and inherits from the VolleyballStats class. Neither adapter class does wrapping. The grayed-out portions of the diagram have not changed logically from figure 10.2.
The model of the alternative version of the Adapter Design Pattern. Compare with figure 10.4. The Adapter class relies on multiple inheritance.
To perform fund raising, classes AthleticsDept and Administration each must call the appropriate methods of classes Alumni, BoosterClubs, and Students.
The architecture modeled from the Façade Design Pattern hides the details of fundraising behind the façade class FundRaiser which presents a higher-level interface that simplifies using the subsystem consisting of classes Alumni, BoosterClubs, and Students.
The generic model of the Façade Design Pattern. Compare with figure 10.7. The Façade class hides the interfaces of the subsystem classes and makes the subsystem consisting of classes Alumni, BoosterClubs, and Students easier to use.
Summary
- The Adapter Design Pattern models a software architecture that converts the interface of the adaptee class to a target interface. This allows integrating codes that weren’t originally designed to work together.
- One version of the Adapter Design Pattern uses object composition to wrap an object of the adaptee class in an adapter class that implements the target interface.
- The other version of the pattern relies on multiple inheritance, where the adapter class implements the target interface and is a subclass of the adaptee class.
- The Façade Design Pattern hides the multiple interfaces of a subsystem of classes with a simpler and higher-level interface, thereby making the subsystem easier to use.
Software Design for Python Programmers ebook for free