Structural Patterns (Adapter & Decorator)
Discover how to assemble objects and classes into larger structures while keeping them flexible and efficient using Adapter and Decorator patterns.
Learning Goals
- Integrate legacy or third-party code using the Adapter pattern.
- Extend object functionality at runtime using the Decorator pattern.
- Differentiate between Inheritance-based and Decorator-based extension.
Organizing Object Relationships
Structural design patterns explain how to assemble objects and classes into larger structures, while keeping these structures flexible and efficient. They help ensure that if one part of a system changes, the entire structure doesn't need to do the same.
1. The Adapter Pattern
The Adapter pattern allows objects with incompatible interfaces to collaborate. It acts as a wrapper between two objects. It catches calls for one object and transforms them to format and interface feel recognizable to the second object.
Real-world analogy: A power adapter that allows a US plug to work in a European socket.
Why use it? When you want to use an existing class, but its interface does not match the one you need, or when you want to use several existing subclasses that lack some common functionality.
2. The Decorator Pattern
The Decorator pattern lets you attach new behaviors to objects by placing these objects inside special wrapper objects that contain the behaviors.
Why use it?
It provides a flexible alternative to sub-classing for extending functionality. Instead of creating a complex hierarchy of classes (e.g., CoffeeWithMilk, CoffeeWithSugar, CoffeeWithMilkAndSugar), you can simply wrap a base Coffee object with a MilkDecorator and a SugarDecorator.
Visualizing Decorator Chaining
Example: A Legacy Data Integration
Suppose you have a modern AnalyticsSystem that expects data in JSON format, but you need to pull data from a LegacyInventory system that only provides XML.
- The Adapter: Create an
InventoryAdapterthat implements the modernIDataProviderinterface (JSON). - The Logic: Internally, the adapter calls the legacy XML service, parses the XML, converts it to JSON, and returns it to the client.
The modern system is completely unaware that it is interacting with a legacy XML component.
Knowledge Check
Which structural pattern is most useful for integrating a third-party library whose interface doesn't match your application's internal standards?