Skip to content

Latest commit

 

History

History

Readme.md

Structural Design Patterns

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.


Table of Contents


Adapter

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 – adapts AdvancedMediaPlayer to MediaPlayer so 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.


Bridge

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 to DrawAPI.
  • Circle – refined abstraction that uses any DrawAPI implementation at runtime.

Typical use case: UI or drawing APIs where shape abstractions and rendering strategies (e.g., API, color, platform) should evolve independently.


Composite

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 of FileSystemComponent objects 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.


Decorator

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 a Coffee.
  • 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.


Facade

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 simple start() 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.


Flyweight

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 of TreeType instances 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.


Proxy

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 delays RealImage creation until display() 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.


Notes

  • 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 main methods that instantiate and wire them together as shown in the comments.