Install
openclaw skills install bookforge-structural-pattern-selectorChoose the right structural design pattern (Adapter, Bridge, Composite, Decorator, Facade, Flyweight, or Proxy) for a structural design problem. Use when you...
openclaw skills install bookforge-structural-pattern-selectorYou have a structural design problem — one about how classes or objects are composed to form larger structures. This skill applies when:
Not this skill if: The problem is about object creation (use a creational pattern) or communication/algorithms between objects (use a behavioral pattern). If you haven't yet classified the problem as structural, invoke design-pattern-selector first.
Problem description: What structural challenge exists? A rough description is fine — "I need these two incompatible classes to work together" or "I'm adding logging/auth to objects without changing them"
Design timing: Is this a new design (before classes exist) or an integration problem (classes already designed and built)?
implements/extends mismatches between incompatible classes → Adapter candidateACTION: Use TodoWrite to track steps, then extract the core structural problem.
WHY: Structural problems often present with symptoms ("this class is too hard to change") rather than causes ("these two abstractions are coupled"). Forcing a structured frame up front prevents jumping to the wrong pattern before the actual problem is clear.
TodoWrite:
- [ ] Step 1: Frame the problem
- [ ] Step 2: Classify the structural intent
- [ ] Step 3: Apply the disambiguation decision tree
- [ ] Step 4: Check pattern-specific applicability conditions
- [ ] Step 5: Produce recommendation with rationale
Capture these elements from the description:
| Element | Question to answer |
|---|---|
| What exists | What classes/objects are already in play? |
| What is wrong | What is currently rigid, mismatched, or inefficient? |
| What must be possible | What should the design enable that isn't possible now? |
| Timing | Are these classes already designed, or is this a fresh design? |
ACTION: Identify which of the seven structural intents best matches the problem.
WHY: Each structural pattern solves a fundamentally different structural problem. Getting the intent right eliminates 5–6 patterns immediately. The intent is the core discriminator — not the implementation mechanics.
Structural intent map:
| Intent | Core problem | Pattern |
|---|---|---|
| Interface translation | Two existing, incompatible interfaces must collaborate | Adapter |
| Abstraction/implementation decoupling | An abstraction must vary independently of how it is implemented | Bridge |
| Part-whole uniformity | Individual objects and compositions must be treated identically | Composite |
| Dynamic responsibility addition | Responsibilities must be added/removed at runtime without subclassing | Decorator |
| Subsystem simplification | A complex set of classes needs one simplified entry point | Facade |
| Instance sharing for efficiency | Large numbers of fine-grained objects must share state to reduce memory cost | Flyweight |
| Controlled/mediated access | Access to an object must be gated, deferred, or monitored | Proxy |
OUTPUT: Identify the 1–2 most matching intents. If two intents match, proceed to Step 3 for disambiguation.
ACTION: For each commonly confused pair, apply the specific discriminator below.
WHY: The structural patterns share implementation mechanics (all use indirection, all involve forwarding calls) but differ sharply in intent and timing. Using the wrong one produces structurally valid but semantically wrong code — Bridge code that should have been Adapter won't adapt; Proxy code that should have been Decorator won't stack.
The single question that separates them:
"Were the classes being connected designed independently before this problem arose, or are you designing the structure now so they can vary independently later?"
Answer: already designed, now incompatible → Adapter
Answer: designing now, need future flexibility → Bridge
Facade vs Adapter distinction: Facade is sometimes described as an adapter for a set of objects. The difference: Facade defines a new interface over an existing subsystem. Adapter reuses an existing interface by making another class conform to it. If clients already know the target interface and you need another class to satisfy it → Adapter. If there is no target interface and you're creating a convenient entry point → Facade.
These three share a structural mechanism: they all wrap another object and forward calls. Differentiate by intent and recursion:
| Question | Composite | Decorator | Proxy |
|---|---|---|---|
| What is the purpose? | Represent part-whole hierarchy (structure) | Add responsibilities dynamically (embellishment) | Control or mediate access (access management) |
| Does it hold multiple children? | Yes — a Composite holds a list of Components | No — a Decorator wraps exactly one Component | No — a Proxy references exactly one Subject |
| Is recursive composition essential? | Yes — the pattern requires it (tree structure) | Yes — decorators can be nested (stacked behaviors) | No — the proxy-subject relationship is static and one-to-one |
| Does the wrapper change behavior? | Yes, by aggregating children | Yes, by adding before/after behavior | Sometimes (protection, logging), but the subject defines core behavior |
| Known at compile time? | Determined at runtime (tree built dynamically) | Determined at runtime (decoration can be applied/removed) | Often known at compile time (proxy-subject relationship is fixed) |
Quick diagnostic:
ACTION: For the leading candidate, verify its specific applicability conditions are met. For Flyweight, ALL five conditions must be true — it is an AND-gate, not an OR-gate.
WHY: Each pattern has conditions that make it inappropriate even when the intent matches. Verifying these prevents applying a pattern that will cause more problems than it solves.
Adapter — use when:
Bridge — use when:
Composite — use when:
Decorator — use when:
Facade — use when:
Flyweight — ALL five conditions must be true (AND-gate):
==) will return true for conceptually distinct objects. If your code needs to distinguish between individual instances that represent different logical entities, Flyweight will break that logic.Proxy — use when:
ACTION: Deliver a structured recommendation, explicitly naming the disambiguation rationale if the problem involved a confused pair.
WHY: A recommendation without the disambiguation rationale leaves the developer unable to defend the choice to teammates, and unable to re-evaluate if the situation changes (e.g., if a design-time Bridge later needs to become an Adapter because existing classes were introduced).
Recommendation format:
## Structural Pattern Recommendation: [Pattern Name]
**Intent match:** [One sentence connecting the pattern's intent to the specific problem]
**Why not [confused alternative]:** [The specific discriminator that ruled it out — timing, recursion, identity, etc.]
**Applicability check:** [Confirm the specific conditions from Step 4 are met]
**What it enables:** [What the design can do after applying this pattern]
**Key trade-off:** [What complexity or constraint this pattern introduces]
**Patterns to combine with:** [Any structural or behavioral patterns that complement this, if applicable]
Scenario: A team is integrating a payment provider's SDK. The SDK's PaymentGateway class has a processCharge(amount, token) method. The application's internal interface is IPaymentProcessor with a charge(request: PaymentRequest) method. The SDK cannot be modified.
Trigger: "We need to use this payment SDK but it doesn't match our internal interface."
Process:
Output:
## Structural Pattern Recommendation: Adapter
**Intent match:** The PaymentGateway SDK already exists with a fixed interface;
Adapter translates the existing IPaymentProcessor interface to the SDK's API
without modifying either.
**Why not Bridge:** Bridge is used before design, to keep two hierarchies from being
permanently coupled. These classes are already built — the incompatibility is
discovered, not anticipated. "Adapter makes things work after they're designed;
Bridge makes them work before."
**Applicability check:** Existing class (SDK) with non-matching interface — confirmed.
Object adapter used because subclassing PaymentGateway is not appropriate.
**What it enables:** The application only ever sees IPaymentProcessor. Swapping
the payment provider means swapping the Adapter class, with zero changes to application code.
**Key trade-off:** Each method added to IPaymentProcessor requires a corresponding
translation in the Adapter. If the interfaces diverge significantly, the Adapter
grows. Consider whether the internal interface can be kept stable.
**Patterns to combine with:** Factory Method (to instantiate the correct Adapter
based on configured payment provider)
Scenario: A document editor has two kinds of graphic objects: primitive shapes (Line, Rectangle, Text) and grouped graphics (Picture, which contains other graphics). The editor needs to move, resize, and draw both primitive and grouped objects through the same interface. Nested groups must work (a Picture can contain another Picture).
Trigger: "We need to treat individual shapes and groups of shapes the same way, including nested groups."
Process:
Output:
## Structural Pattern Recommendation: Composite
**Intent match:** The editor needs to treat individual shapes and grouped shapes
uniformly through a Graphic interface, with arbitrarily deep nesting of groups.
**Why not Decorator:** Decorator also uses recursive composition but its purpose
is embellishment — adding behaviors. Composite's purpose is representation —
organizing objects into a tree where nodes and leaves are interchangeable.
No responsibilities are being added here; a structure is being organized.
**Why not Proxy:** Proxy is a one-to-one stand-in for one Subject, not a
container for multiple children.
**Applicability check:** Part-whole hierarchy (Picture contains Graphics) and
uniform client treatment (editor calls draw() on any Graphic) — both confirmed.
**What it enables:** The editor code can call draw(), move(), or resize() on any
Graphic without knowing whether it's a primitive or a group. Adding new primitive
types requires no changes to the editor.
**Key trade-off:** Makes the design overly general — it becomes hard to restrict
what can be added to a Composite (e.g., preventing a Line from being added as a
child of a TextGroup). If type-safety in the hierarchy matters, extra validation
is needed.
**Patterns to combine with:** Decorator (to add responsibilities to individual
Graphic objects without subclassing), Iterator (to traverse the tree)
Scenario: A developer has a ReportService that generates reports. They need to add rate limiting (no more than 10 calls per minute), request logging, and authentication checking — all without modifying ReportService. The behaviors may need to be applied in different combinations to different service instances.
Trigger: "I need to add rate limiting, logging, and auth to our service without touching the service class, and I need to be able to mix and match which ones apply."
Process:
Output:
## Structural Pattern Recommendation: Decorator
**Intent match:** Rate limiting, logging, and auth are responsibilities that need
to be added dynamically and in different combinations — exactly what Decorator
is designed for. Each concern becomes a decorator wrapping the service.
**Why not Proxy:** Proxy controls access through a static one-to-one relationship
to one Subject. It is not designed for recursive composition or for mixing and
matching multiple behaviors. A ProtectionProxy could handle auth alone, but cannot
stack with a RateLimitingProxy without compromising both patterns' intent.
**Applicability check:** Responsibilities are to be added transparently without
affecting other objects; responsibilities can be withdrawn (remove a decorator to
remove the behavior); subclassing for all combinations is impractical (3 behaviors
= 7 possible combinations). Confirmed.
**What it enables:** RateLimitingDecorator(LoggingDecorator(AuthDecorator(reportService)))
composes all three behaviors. Each can be added or removed independently at
construction time.
**Key trade-off:** A decorator and its component are not identical objects — code
that uses object identity (==) to find a specific layer will fail. Also, many small
objects can be harder to debug (stepping through the decorator chain). Keep
decorator chains short and document the wrapping order.
**Patterns to combine with:** Factory Method (to construct the right decorator
combination based on configuration)
Timing is the Adapter/Bridge axis — "Adapter makes things work after they're designed; Bridge makes them work before." If the incompatibility was discovered (classes already exist), that's Adapter territory. If the separation is intentional design-time planning, that's Bridge territory.
Intent beats mechanics — Composite, Decorator, and Proxy all wrap objects and forward calls. The right choice is determined by what you're trying to accomplish: structure a hierarchy (Composite), add behaviors (Decorator), or control access (Proxy). Choosing by implementation similarity produces structurally valid but semantically wrong code.
Flyweight is an AND-gate, not an OR-gate — All five conditions must hold simultaneously. The most commonly missed is identity: if any part of the application needs to distinguish between two flyweight instances representing different logical entities, shared objects will cause silent correctness bugs.
Facade defines new; Adapter reuses existing — Facade creates a convenient new interface over a subsystem where none existed. Adapter makes a class conform to an existing interface someone else owns. If clients already have a target interface they code to, it's Adapter. If you're inventing the interface, it's Facade.
Recursive composition signals Composite or Decorator, not Proxy — Proxy's subject relationship is static and one-to-one. If the design requires stacking, nesting, or building trees of wrapped objects, the choice is between Composite (structural hierarchy) and Decorator (behavioral layering), not Proxy.
design-pattern-selector/references/pattern-catalog.mdThis skill is licensed under CC-BY-SA-4.0. Source: BookForge — Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides.
Install related skills from ClawhHub:
clawhub install bookforge-design-pattern-selectorOr install the full book set from GitHub: bookforge-skills