This package contains simplified Java implementations of the Structural Design Patterns from the Gang of Four (GoF).
Structural patterns describe how classes and objects are composed to form larger structures, while keeping these structures flexible and efficient.
Intent: Convert the interface of a class into another interface that clients expect, so that classes with incompatible interfaces can work together.
In this package: Adapter.java defines:
MediaPlayer– existing client-facing interface.AdvancedMediaPlayer– richer interface for advanced players.VlcMediaPlayer– concrete advanced player.MediaAdapter– adaptsAdvancedMediaPlayertoMediaPlayerso VLC files can be played via the simple interface.
Typical use case: Integrating a new library (e.g., VLC player) into an existing media-player API without changing client code.
Intent: Decouple an abstraction from its implementation so that the two can vary independently.
In this package: Bridge.java demonstrates:
DrawAPI– implementation hierarchy (e.g.,RedCircle,BlueCircle).Shape– abstraction that delegates drawing toDrawAPI.Circle– refined abstraction that uses anyDrawAPIimplementation at runtime.
Typical use case: UI or drawing APIs where shape abstractions and rendering strategies (e.g., API, color, platform) should evolve independently.
Intent: Compose objects into tree structures to represent part–whole hierarchies, allowing clients to treat individual objects and compositions uniformly.
In this package: Composite.java defines a simple file system:
FileSystemComponent– common component interface (display,getSize).File– leaf node representing an individual file.Directory– composite that holds a list ofFileSystemComponentobjects and forwards operations to its children.
Typical use case: File systems, UI component trees, or any structure where single items and groups should be handled through the same API.
Intent: Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
In this package: Decorator.java models a coffee-ordering example:
Coffee– base component interface.SimpleCoffee– core implementation.CoffeeDecorator– base decorator that wraps aCoffee.Milk,Sugar– concrete decorators that add cost and description.
Typical use case: Adding cross-cutting features (options, behaviors) to objects at runtime, such as UI borders, logging, or pricing add‑ons.
Intent: Provide a unified, high-level interface to a subsystem, making it easier to use.
In this package: Facade.java contains a computer start-up example:
- Subsystem classes:
CPU,Memory,HardDrive. ComputerFacade– orchestrates the complex start-up sequence (freeze,load,jump,execute) behind a simplestart()call.
Typical use case: Simplifying interaction with complex libraries or subsystems (e.g., media conversion, system boot process) behind a single easy-to-use API.
Intent: Minimize memory usage by sharing as much data as possible with similar objects; separate intrinsic (shared) from extrinsic (context-specific) state.
In this package: Flyweight.java shows a tree example:
Tree– flyweight interface.TreeType– concrete flyweight storing intrinsic state (name,color) and rendering at coordinates.TreeFactory– ensures reuse ofTreeTypeinstances for the same name+color combination.
Typical use case: Large numbers of similar objects (e.g., trees in a forest, characters in a document) where shared state can be reused to save memory.
Intent: Provide a surrogate or placeholder for another object to control access to it.
In this package: Proxy.java demonstrates a virtual image proxy:
Image– subject interface.RealImage– real subject that loads an image from disk on creation.ProxyImage– proxy that delaysRealImagecreation untildisplay()is first called and then delegates subsequent calls.
Typical use case: Lazy loading, access control, remote proxies, or logging wrappers around expensive or sensitive objects.
- All examples are intentionally lightweight and focused on illustrating the core structure of each pattern.
- To experiment, you can extract these inner classes into separate files and add small
mainmethods that instantiate and wire them together as shown in the comments.