DEV Community

Cover image for Design pattern visualization: Structural Design Patterns
Gokul G.K.
Gokul G.K.

Posted on

Design pattern visualization: Structural Design Patterns

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

Adapter Gif

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.

Universal power adapter

Class Diagram

Adapter 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 the specificRequest() method the Adaptee understands.

Bridge

Bridge Gif

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

Bridge 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 Implementor object. 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., a Circle or Square class 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 Implementor provides primitive operations, while the Abstraction defines higher-level operations based on those primitives.
  • ConcreteImplementor (A/B): The specific, concrete classes that carry out the actual work (e.g., the Red or Blue color classes).

Composite

Composite Gif

Composite is a structural design pattern that allows you to combine objects into tree structures and treat them as individual entities.

Class Diagram

Composite 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 Component interface, 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 Component interface and defines the behavior of the operation() 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 Component interface. When operation() is called on a Composite, it typically iterates over its children and delegates the work to them.

Decorator

Decorator Gif

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

Decorator 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 Component interface. It doesn't need to know whether it is working with a plain ConcreteComponent or 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 Component interface (e.g., the plain black coffee).
  • Decorator: An abstract class that implements the Component interface 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 Decorator to add new, specific behaviors or state. They override the operation() method to execute their custom code either before or after delegating the rest of the work to the wrapped component.

Facade

Facade Gif

A facade is a design pattern that provides a simplified interface to complex libraries, frameworks, or classes.

Class Diagram

Facade 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 the Facade exists—they don't hold references back to it.

Flyweight

Flyweight Gif

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

Flyweight 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 Flyweight interface 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 Flyweight interface 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

Proxy 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 RealSubject and the Proxy. 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 proxy finally 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, the proxy intercepts 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 the RealSubject.

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.