Refactoring Guru already has the best blog to learn Design patterns. Here I am just trying to give a brief about each design.
Design patterns are solutions to recurring problems and design paradigms.
Structural design patterns describe how to combine objects and classes into larger structures while maintaining flexibility and efficiency.
You can get the Java code here or some detailed examples.
Let's dive into each one.......
Adapter
An adapter is a design pattern that allows objects with incompatible interfaces to work together effectively.
Rather than a rail-to-car adaptor (which sounds like AI-generated, which it isn't), a universal power adaptor is the best real-world example.
Class Diagram
The Adapter pattern acts as a bridge between two incompatible interfaces. Just like a physical travel adapter allows a European plug to work in a US wall outlet, the software Adapter allows classes with mismatched interfaces to work together smoothly.
- Client: The class that wants to interact with a system using a specific, expected interface (the Target).
- Target: The interface or abstract class that the Client understands and expects to work with. It defines the standard
request()method. - Adaptee: The existing, already-built class that contains the functionality the Client needs, but it has an incompatible interface (like
specificRequest()). - Adapter: The bridge class. It implements the Target interface so the Client can use it, but under the hood, it holds a reference to the Adaptee and translates the
request()method into thespecificRequest()method the Adaptee understands.
Bridge
A bridge is a design pattern that allows separating a large class or a set of related classes into two distinct hierarchies: abstraction and implementation, which can be developed independently.
Class Diagram
The Bridge pattern separates a class's interface (its abstraction) from its implementation, allowing both to be modified independently without breaking client code. This is particularly useful for preventing a "Cartesian product" explosion of classes (for example, instead of creating RedCircle, BlueCircle, RedSquare, and BlueSquare, create a Shape abstraction that holds a bridge to a Color implementor).
- Client: The code that uses the system. It only interacts with the Abstraction and doesn't need to know anything about the underlying implementations.
- Abstraction: The high-level control layer. It defines the basic interface for the client and maintains a reference to an
Implementorobject. It delegates the actual work to this implementor. - RefinedAbstraction: A specific variant or extension of the
Abstraction. It implements the specific behaviors of the high-level entity (e.g., aCircleorSquareclass extending a general Shape class). - Implementor: The interface for all implementation classes. It doesn't have to match the Abstraction's interface at all; typically, the
Implementorprovides primitive operations, while theAbstractiondefines higher-level operations based on those primitives. - ConcreteImplementor (A/B): The specific, concrete classes that carry out the actual work (e.g., the
RedorBluecolor classes).
Composite
Composite is a structural design pattern that allows you to combine objects into tree structures and treat them as individual entities.
Class Diagram
The Composite pattern is used to represent part-whole hierarchies as tree structures. Its primary superpower is that it allows the client code to treat individual objects (leaves) and compositions of objects (branches/nodes) in the exact same way. Think of a file system: a folder (Composite) and a file (Leaf) can both be moved, deleted, or renamed (Component operations), even though a folder contains other files and folders.
- Client: The code that interacts with the objects in the tree structure. It uses the
Componentinterface, meaning it doesn't need to check whether it's dealing with a single object or a complex group. - Component: The base interface or abstract class for all objects in the composition. It defines common operations (such as
operation()) and usually includes methods for adding, removing, or accessing child components. - Leaf: The basic, building-block object that has no children. It implements the
Componentinterface and defines the behavior of theoperation()method. In a file system, this is the individual file. - Composite: The complex object that contains child components (which can be Leaves or other Composites). It implements the
Componentinterface. Whenoperation()is called on a Composite, it typically iterates over its children and delegates the work to them.
Decorator
A decorator is a design pattern that allows you to attach new behaviors to objects by placing them inside special wrapper objects that include those behaviors.
Class Diagram
The Decorator pattern allows you to attach new behaviors or responsibilities to an object dynamically at runtime, without altering its structure or relying on massive subclassing. Think of it like ordering a plain coffee and then adding "decorations" like milk, sugar, and caramel—each addition wraps the original object and adds its own flavor, but it is still fundamentally a coffee.
- Client: The code that interacts with objects through the standard
Componentinterface. It doesn't need to know whether it is working with a plainConcreteComponentor one wrapped in multiple decorators. - Component: The common interface or abstract class for both the core objects and the decorators. It defines the standard methods (like
operation()) that can be used or overridden. - ConcreteComponent: The base, standalone object to which new behaviors can be added. It implements the basic behavior defined in the
Componentinterface (e.g., the plain black coffee). - Decorator: An abstract class that implements the
Componentinterface and simultaneously contains a reference (or wrapper) to a Component object. Its primary job is to delegate all requests to the wrapped component by default. - ConcreteDecorator (A/B): The classes that extend the base
Decoratorto add new, specific behaviors or state. They override theoperation()method to execute their custom code either before or after delegating the rest of the work to the wrappedcomponent.
Facade
A facade is a design pattern that provides a simplified interface to complex libraries, frameworks, or classes.
Class Diagram
The Facade pattern provides a simplified, unified interface to a complex set of underlying subsystems. Think of it like a smart home hub: instead of having to manually turn on the lights, roll down the blinds, and turn on the TV with three different remotes, the hub gives you a single "Movie Mode" button (the Facade) that handles all the complex underlying interactions for you.
- Client: The code that needs to interact with the complex subsystem. Instead of managing dozens of individual subsystem classes, it simply calls the easy-to-use methods provided by the
Facade. - Facade: The "front-facing" class that provides the simplified interface. It knows exactly which subsystem classes are responsible for a request and delegates the client's command to the appropriate places in the correct order.
- Subsystem Classes (A/B/C): The complex, underlying classes that do the actual, heavy-lifting work. They handle the specific tasks assigned by the
Facade. Importantly, these classes operate independently and have no knowledge that theFacadeexists—they don't hold references back to it.
Flyweight
A flyweight is a design pattern that allows you to fit more objects into available RAM by sharing common parts of their state among multiple objects rather than storing all data in each one.
Class Diagram
The Flyweight pattern is all about memory optimization. It allows you to fit more objects into the available RAM by sharing common parts of state across multiple objects, rather than keeping all the data in each individual object. Think of a word processor: instead of creating a brand new object for every single letter "e" in a document (which would eat up memory), the system creates exactly one "e" object that holds the font shape (the shared, unchanging data). The exact coordinates on the page where that "e" appears (the unique, changing data) are passed in from the outside.
- Client: The code that uses the flyweights. It calculates or stores the "extrinsic" state (the unique context, like the coordinates of a letter on a page) and passes it to the flyweight's methods when needed.
- FlyweightFactory: A manager class that creates and maintains a pool of flyweight objects. When a client requests a flyweight, the factory checks if one already exists. If it does, it returns the existing instance; if not, it creates a new one, adds it to the pool, and returns it.
- Flyweight: The interface or abstract class that defines how flyweights can receive and act on extrinsic state passed in by the client.
ConcreteFlyweight: The object that implements the
Flyweightinterface and stores the "intrinsic" state. This state must be immutable (unchanging) and shared across all contexts.UnsharedConcreteFlyweight: The pattern allows for flyweights that aren't actually shared. Sometimes you have an object that implements the
Flyweightinterface so it can be treated uniformly by the client, but it maintains all of its own state internally rather than sharing it.
Proxy
A proxy is a design pattern that allows you to create a substitute or placeholder for another object. It manages access to the original object, enabling you to perform an operation before or after the request is sent to it.
Class Diagram
The Proxy pattern provides a surrogate or placeholder for another object, allowing it to control access to that object. While it looks structurally very similar to the Decorator or Adapter patterns, its intent is different: an Adapter changes the interface, a Decorator adds behavior, but a Proxy controls access. Think of a company credit card: it acts as a proxy for the company's bank account. Both the card and the account share the same "payment" interface, but the card controls access, perhaps imposing limits or logging transactions before interacting with the actual funds.
- Client: The code that needs to use the real object. Because it interacts strictly with the Subject interface, it doesn't know (and doesn't need to know) whether it is talking to the RealSubject or the
Proxy. - Subject: The common interface shared by both the
RealSubjectand theProxy. This ensures the proxy can be used interchangeably anywhere the real object is expected. - RealSubject: The actual, underlying object that contains the real business logic or heavy resource. It actually handles the work when the
proxyfinally passes the request along. - Proxy: The middleman. It implements the Subject interface and holds a reference to the
RealSubject. When the client makes a request, theproxyintercepts it. It might check access permissions, log the request, handle lazy loading (delaying the creation of a heavy' RealSubject' until it is absolutely needed), and ultimately delegate the work to theRealSubject.
Structural Design Patterns: Real-World & Technical Examples
| Design Pattern | What it does (The "TL;DR") | Real-World Analogy | Technical Application |
|---|---|---|---|
| Adapter | Acts as a bridge between two incompatible interfaces, allowing them to work together. | A travel plug adapter that allows a US laptop charger to fit into a European wall outlet. | Wrapping a legacy XML-based billing API so it can be used by a modern JSON-based microservice. |
| Bridge | Separates an abstraction (interface) from its implementation, allowing the two to vary independently. | A universal remote (abstraction) that can be paired with different TV brands (implementations). | A UI framework where a Button abstraction delegates its rendering to underlying OS-specific (Windows/macOS) implementations. |
| Composite | Composes objects into tree structures to represent part-whole hierarchies, treating individual objects and groups uniformly. | A shipping box that contains individual products as well as smaller boxes, which in turn contain more products. | A file system where both Directory and File share a common interface for operations like getSize() or delete(). |
| Decorator | Dynamically attaches new responsibilities or behaviors to an object without altering its underlying structure. | Ordering a basic coffee and adding "decorators" like milk, caramel syrup, and whipped cream. | Wrapping a base FileDataReader with a CompressionDecorator and an EncryptionDecorator before saving to a database. |
| Facade | Provides a simplified, higher-level interface to a complex subsystem of classes. | A smart home hub's "Movie Mode" button automatically dims lights, closes blinds, and turns on the TV. | A simple VideoConverter class that hides the complex interactions of underlying audio/video codec libraries and buffer management. |
| Flyweight | Minimizes memory usage by sharing as much data as possible with similar objects, rather than keeping all data in each object. | Using a single master blueprint to build a massive neighborhood of structurally identical houses. | A text editor that loads a single instance of a character glyph (like the letter "e") into memory and reuses it, only passing its unique X/Y coordinates on the screen. |
| Proxy | Provides a surrogate or placeholder to control access to the original object. | A credit card acting as a proxy for your bank account—it controls access to your funds and enforces limits. | A LazyImageLoader that displays a lightweight placeholder icon on a webpage until the user scrolls down, at which point it loads the heavy, high-res image. |














Top comments (1)
Some comments may only be visible to logged-in visitors. Sign in to view all comments.