Structural Patterns
Learn how Java structural patterns reshape interfaces, layer behavior, and model object relationships without defaulting to rigid inheritance trees.
Structural patterns are about shape. In Java, they help you decide how types should relate to each other when the pressure is not object creation or workflow sequencing, but interface mismatch, layering, composition, access control, or hierarchy management.
This chapter treats structural patterns as design tools, not museum pieces. Some of them map directly to everyday Java work:
Adapter when you must integrate an incompatible API cleanlyBridge when abstraction and implementation are changing independentlyComposite when clients should treat single objects and trees uniformlyDecorator when behavior should be layered without multiplying subclassesFacade, Proxy, and Flyweight when subsystem shape, access boundaries, or memory pressure become the main design problem
The important question is not whether a class diagram matches the Gang of Four illustration perfectly. The important question is whether the pattern clarifies the boundary the code actually has.
Read the chapter with three review questions in mind:
- What is the structural problem here?
- Does the pattern reduce coupling or just move it around?
- Would idiomatic Java tools such as interfaces, composition, records, or standard library wrappers already solve most of the problem?
When structural patterns are applied well, they make large Java systems easier to extend. When applied mechanically, they produce wrapper layers nobody wants to debug.
In this section
- Introduction to Structural Patterns in Java Design
Understand what Java structural patterns solve, when they beat inheritance, and how to choose among wrappers, bridges, composites, decorators, facades, and proxies.
- Adapter Pattern
Use the Adapter pattern in Java when clients already have the right contract and a dependency needs translation into it.
- Bridge Pattern
Use the Bridge pattern in Java when abstraction and implementation need to vary independently instead of multiplying subclasses.
- Composite Pattern
Use the Composite pattern in Java when clients should work with single objects and recursive groups through one common contract.
- Implementing Composite in Java
Implement Composite in Java with a clear component contract, disciplined child ownership, and traversal rules that fit recursive structures.
- Component, Leaf, and Composite Classes
Design the three Composite roles in Java deliberately so the shared contract stays useful and child-management rules stay explicit.
- Managing Hierarchical Structures with the Composite Pattern
Manage Java composite hierarchies with explicit ownership, cycle rules, mutation boundaries, and aggregation semantics.
- Iteration and Recursion in Composites
Choose traversal style for Java composites deliberately, balancing recursion, explicit iterators, streams, and failure handling.
- Composite Pattern Use Cases and Examples in Java
See where Composite earns its place in Java systems, especially UI trees, file-like hierarchies, bundles, and recursive rule structures.
- Decorator Pattern
Use the Decorator pattern in Java when behavior should be layered by wrapping instead of multiplying subclasses.
- Implementing Decorator Pattern in Java
Implement Java decorators by wrapping a small interface, delegating cleanly, and keeping each added behavior narrow and explicit.
- Interface-Based Decorators
Keep Java decorators practical by decorating narrow interfaces rather than large concrete types with sprawling method surfaces.
- Chaining Decorators
Chain Java decorators deliberately, because wrapper order changes behavior, visibility, performance, and failure semantics.
- Decorator vs. Inheritance
Compare Decorator with inheritance in Java and choose the one that matches variation shape, optional behavior, and runtime composition needs.
- Decorator Pattern Use Cases and Examples in Java
See where Decorator genuinely helps in Java, from I/O wrappers and handlers to logging, metrics, caching, and authorization layers.
- Facade Pattern
Use the Facade pattern in Java to present a simpler subsystem boundary without pretending the subsystem itself has disappeared.
- Flyweight Pattern
Use the Flyweight pattern in Java when large numbers of similar objects make shared immutable state worth the extra discipline.
- Proxy Pattern
Use the Proxy pattern in Java when access, laziness, remoteness, or policy must stand between the client and a real object.
- Implementing Proxy in Java
Implement Java proxies by preserving the original contract while controlling access, creation, or invocation of the real object.
- Types of Proxies in Java
Distinguish virtual, protection, and remote proxies in Java so the access concern is explicit instead of buried in a generic wrapper.
- Dynamic Proxies in Java
Use Java dynamic proxies when cross-cutting behavior should wrap many interface implementations without hand-writing one proxy class per type.
- Proxy vs. Decorator Pattern
Compare Proxy and Decorator in Java so access control and optional behavior layering are not treated as the same design move.
- Proxy Pattern Use Cases and Examples in Java
See where Proxy genuinely helps in Java systems, from remote clients and security wrappers to lazy loading and caching access boundaries.
- Private Class Data Pattern
Use Private Class Data in Java when internal state must be grouped and protected from accidental exposure or inconsistent mutation.
- Marker Interfaces and Annotations
Compare marker interfaces and annotations in Java so metadata and framework signaling stay explicit and modern.
- Extension Object Pattern
Use the Extension Object pattern in Java when objects need optional capabilities without forcing every capability into the main type hierarchy.