11 Structural Patterns

Structural Patterns

Objective

  1. Structural design patterns.

Design Patterns

Design patterns are proven, reusable solutions to common problems that occur in software design. They represent best practices that experienced developers have refined over time, and they can be adapted to fit various situations. Each pattern provides a standard template for solving specific design challenges, which helps streamline the development process and improve code maintainability and scalability.

Design patterns offer several benefits:

  1. Promote reusability: By using design patterns, developers can apply tried-and-true approaches to solve problems more efficiently without reinventing the wheel.
  2. Enhance code maintainability: Well-structured solutions simplify future modifications and reduce the risk of bugs when making changes.
  3. Improve communication: Design patterns provide a common vocabulary for developers, making it easier to discuss and share ideas.
  4. Facilitate scalability: Patterns often enable systems to be designed with future growth and additional functionality in mind.
  5. Enforce best practices: Using patterns encourages developers to adhere to proven coding principles, which results in more robust and reliable software.

Design patterns are generally categorized into three main types:

  1. Creational patterns: Focus on the process of object creation.
  2. Structural patterns: Deal with object composition and the relationships between entities to create larger, more complex structures.
  3. Behavioral patterns: Concerned with the interaction and responsibility between objects.

By applying the appropriate design patterns, developers can create more maintainable, flexible, and efficient code that aligns with established best practices.

Code refactoring refers to the process of restructuring an existing codebase without changing its external behavior, while ensuring that the corresponding UML diagrams, such as class, sequence, or activity diagrams, are updated to reflect these changes. This practice helps improve the design, structure, and maintainability of the software.

Refactoring might involve:

  1. Reorganizing class structures: Modifying class hierarchies or relationships (e.g., extracting a superclass, merging classes) to make the design clearer and reduce duplication.
  2. Improving method cohesion: Splitting or merging methods, adjusting their interactions in sequence diagrams to enhance code readability and reduce complexity.
  3. Renaming elements: Updating class, attribute, or method names in both the code and UML diagrams to make them more meaningful.
  4. Encapsulation adjustments: Modifying access controls or moving methods between classes while updating diagrams to match.
  5. Simplifying interactions: Streamlining complex process flows represented in activity or sequence diagrams by refactoring logic.

Overall, the goal of code refactoring is to maintain consistent documentation and improve the system’s design quality without altering the end functionality.

“There are so many variations on the “there are only two hard problems in computer programming…” joke that I’m starting to suspect that programming isn’t actually very easy.” —Nat Pryce

Structural Patterns

Adapter

How can we make incompatible interfaces work together? For example, a legacy system that needs to interact with a new system or a third-party library that needs to be integrated into an existing codebase such as a payment gateway.

  • Need to integrate legacy code with new systems
  • Must work with third-party libraries that have incompatible interfaces
  • Want to reuse existing functionality with a different interface

Bridge

How can we separate an abstraction from its implementation so both can vary independently? For example, a drawing application that can render shapes in different ways or a database driver that can connect to multiple databases.

  • Need to extend a class in several independent dimensions
  • Want to avoid a permanent binding between interface and implementation
  • Implementation details should be hidden from the client

Composite

How can we treat individual objects and compositions of objects uniformly? For example, a file system that can contain files and directories or a graphical user interface that can contain components and containers.

  • Need to represent part-whole hierarchies
  • Clients should treat individual objects and compositions identically
  • Want to create tree-like structures of objects

Decorator

How can we add new behaviors to objects dynamically without altering their structure? For example, a text editor that can add spell-checking, a game that can add new abilities to characters, or a food ordering system that can add toppings or sides.

  • Need to extend object functionality at runtime
  • Want to avoid subclass explosion
  • Responsibilities should be added flexibly

Façade

How can we provide a simplified interface to a complex subsystem? For example, a computer that can boot up with a single button press or a library that can handle multiple file formats.

  • Need to provide a simple interface to a complex system
  • Want to reduce dependencies between client and subsystem
  • System complexity should be hidden from clients

Flyweight

How can we minimize memory usage by sharing common parts of state between multiple objects? For example, a text editor that reuses font objects or a game that reuses sprite and three-dimensional objects.

  • Need to support large numbers of similar objects
  • Memory is a constraint
  • Object state can be divided into shared and unique parts

Proxy

How can we control access to an object by providing a surrogate or placeholder? For example, a remote proxy that can access objects in a different address space or a virtual proxy that can load objects on demand such as lazy-loading images.

  • Need to control access to an object
  • Want to add functionality when accessing an object
  • Object creation and access should be managed

Exercise 1

Design class diagrams that use at least three structural design patterns.

Explore the 10 SOLID + GRASP guide to learn more about the SOLID principles and GRASP patterns.

Structure

      • adapter.pat
      • decorator.pat
      • proxy.pat
      • structural.vpp
  • Resources