Token导航 LogoToken导航

Agent Skill · 研究检索

bookforge-composite-pattern-implementor(Bookforge 复合模式实现者)

bookforge-composite-pattern-implementor 用于查找、检索和筛选相关信息,适合在 OpenClaw 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

bookforge-composite-pattern-implementor 是研究检索类 Agent Skill,可用宿主为 OpenClaw,通过ClawHub获取,权限为调用外部服务;许可证为 MIT-0,第三方扫描已通过,按安装量在研究检索类的 73,675 个 Skill 里排第 24,940。

总安装 3,881周安装 157GitHub Stars 公开资料未说明下载 1,218核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT-0
版本
1.0.0

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:bookforge-composite-pattern-implementor(Bookforge 复合模式实现者)
来源仓库:https://github.com/quochungto/bookforge-composite-pattern-implementor
安装命令:
openclaw skills install bookforge-composite-pattern-implementor
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 OpenClaw 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

ClawHubOpenClaw
openclaw skills install bookforge-composite-pattern-implementor

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

实现复合模式构建部分-整体层次结构树。支持统一处理单个对象与组合对象的客户端逻辑。适用于文件系统、UI控件树等层级化场景。安装命令:openclaw skills install bookforge-composite-pattern-implementor 需明确对象类型及组合规则方可应用。

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 OpenClaw;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 openclaw skills install bookforge-composite-pattern-implementor;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要调用外部服务,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

bookforge-composite-pattern-implementor 怎么安装?

在终端执行 openclaw skills install bookforge-composite-pattern-implementor。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

bookforge-composite-pattern-implementor 支持哪些 AI 工具?

公开资料标注支持 OpenClaw。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

bookforge-composite-pattern-implementor 需要什么权限?

权限级别是调用外部服务。该 Skill 可能调用第三方服务、云服务或外部模型 API,使用前需要确认账号、额度、数据发送范围和服务条款。

bookforge-composite-pattern-implementor 是免费的吗?

来源标注的许可证是 MIT-0。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

bookforge-composite-pattern-implementor 用的人多吗?

公开数据是累计安装 3,881 次,近一周安装 157 次,下载 1,218 次。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

bookforge-composite-pattern-implementor 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 专注 OpenClaw 一种宿主,触发方式和使用习惯不用来回切换。
  • 许可证明确为 MIT-0,商用和分发边界好判断。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 OpenClaw,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。
  • 需要许可证清楚、并且有第三方扫描结果的团队项目。

不太适合

  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
bookforge-composite-pattern-implementor

Bookforge 复合模式实现者 · 本页

3,881—调用外部服务MIT-0通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

name
composite-pattern-implementor
description
|
version
1.0.0
homepage
https://github.com/bookforge-ai/bookforge-skills/tree/main/books/design-patterns-gof/skills/composite-pattern-implementor
metadata
{"openclaw":{"emoji":"📚","homepage":"https://github.com/bookforge-ai/bookforge-skills"}}
status
draft
depends-on
source-books
title
Design Patterns: Elements of Reusable Object-Oriented Software
authors
["Erich Gamma", "Richard Helm", "Ralph Johnson", "John Vlissides"]
chapters
[4]
pages
[156-165, 43-48]
tags
[design-patterns, structural, gof, composite, tree, hierarchy, recursion, refactoring]
execution
tier
2
mode
full
inputs
description
Existing code that distinguishes between primitive and container objects with separate handling paths, or a description of a part-whole hierarchy to model
tools-required
[TodoWrite, Read]
tools-optional
[Grep, Edit]
mcps-required
[]
environment
Any codebase. Language-agnostic — examples use Python but the pattern applies universally.

Composite Pattern Implementor

When to Use

You need to model a part-whole hierarchy where clients should be able to treat leaf objects and composite objects the same way — without type-checking or branching on "is this a container or a primitive?"

Apply this skill when:

  • Code that operates on a structure must repeatedly ask "is this a single item or a group?" to decide what to do — the primary code smell
  • You want to represent hierarchies like: file systems (files and directories), UI trees (widgets and panels), org charts (employees and departments), document structures (characters, rows, columns), or bill-of-materials (parts and assemblies)
  • A recursive containment relationship exists: containers can hold other containers as well as primitives
  • New kinds of components should be addable without changing client traversal code

Two applicability conditions (from GoF):

  1. You want to represent part-whole hierarchies of objects
  2. You want clients to be able to ignore the difference between compositions of objects and individual objects — clients will treat all objects in the composite structure uniformly

Before starting, confirm you are not looking for Decorator (which adds responsibilities to a single object, not a tree), or Iterator (which traverses but does not define the containment structure).


Process

Step 1: Set Up Tracking and Identify the Hierarchy

ACTION: Use TodoWrite to track progress, then identify the part-whole structure that needs to be modeled.

WHY: The shape of the hierarchy — how many levels deep, whether ordering matters, whether nodes can have multiple parents — governs all subsequent design decisions. Capturing this upfront prevents discovering structural constraints mid-implementation that force revisiting earlier steps.

TodoWrite:
- [ ] Step 1: Identify the hierarchy and characterize its nodes
- [ ] Step 2: Design the Component interface
- [ ] Step 3: Implement Leaf classes
- [ ] Step 4: Implement the Composite class
- [ ] Step 5: Make the safety-vs-transparency decision
- [ ] Step 6: Apply implementation concerns (parent refs, caching, ordering, deletion)
- [ ] Step 7: Validate the refactored structure

Document the hierarchy:

ElementWhat to capture
Primitive nodesWhat are the leaf types? What operations do they perform?
Container nodesWhat are the composite types? Do containers vary in type (e.g., Bus vs. Cabinet)?
Shared operationsWhich operations must both leaves and composites support?
Child orderingDoes sequence matter (parse trees, rendered rows) or is it a set?
SharingCan a node appear under multiple parents?
DepthIs the nesting depth bounded or unbounded?

If working from a description rather than existing code, sketch the object tree showing two or three levels of nesting before writing any classes.


Step 2: Design the Component Interface

ACTION: Define the abstract Component class — the common interface for both Leaf and Composite objects.

WHY: The Component interface is what enables uniform treatment. When all objects in the hierarchy share this interface, client code can invoke operations without knowing whether it holds a leaf or a composite. If the interface is too narrow, clients must downcast; if too wide, leaf implementations are burdened with operations that have no meaning for them. The goal is to maximize what can be defined here — every operation moved to Component is an operation clients never need to branch on.

Design the interface by listing operations in two categories:

CategoryOperationsWhere declared
Domain operationsDraw(), NetPrice(), Render(), Execute() — operations meaningful to every nodeComponent — always
Child managementAdd(Component), Remove(Component), GetChild(int) — structural operations for compositesComponent or Composite — see Step 5

Maximizing the Component interface: Some operations appear to belong only to Composites (e.g., accessing children). However, if you model a Leaf as a Component that *never has children*, you can define a default GetChild() on Component that returns nothing, and Composites override it to return their children. This keeps clients ignorant of the distinction. Do this for read-only structural operations. The add/remove write operations are more controversial — see Step 5.

from abc import ABC, abstractmethod
from typing import Optional

class Component(ABC):
    """Abstract base for all nodes in the part-whole hierarchy."""

    @abstractmethod
    def operation(self) -> str:
        """Domain operation — implemented by every node."""
        ...

    def add(self, component: "Component") -> None:
        """Default: raise or no-op. Composite overrides."""
        raise NotImplementedError("Leaf components do not support add()")

    def remove(self, component: "Component") -> None:
        """Default: raise or no-op. Composite overrides."""
        raise NotImplementedError("Leaf components do not support remove()")

    def get_child(self, index: int) -> Optional["Component"]:
        """Default: return None. Composite overrides."""
        return None

Step 3: Implement Leaf Classes

ACTION: Create one Leaf class per primitive node type. Each implements the domain operation(s) and does not override child management.

WHY: Leaves are the base cases of the recursive structure — they do actual work. They represent the primitives of the composition: FloppyDisk, Character, Employee, File. Keeping leaves simple is the key benefit: a client can hold a Component reference and call operation() without knowing it is a leaf.

class Leaf(Component):
    """Represents a primitive object — has no children."""

    def __init__(self, name: str):
        self._name = name

    def operation(self) -> str:
        return f"Leaf({self._name})"

In the Equipment hierarchy (GoF sample code):

class FloppyDisk(Component):
    """Leaf — a single hardware component with no subparts."""

    def __init__(self, name: str, wattage: int, price: float):
        self._name = name
        self._wattage = wattage
        self._price = price

    def net_price(self) -> float:
        return self._price   # Leaf's price is its own price — no summation needed

    def power(self) -> int:
        return self._wattage

Step 4: Implement the Composite Class

ACTION: Create the Composite class that stores and manages child components, and implements domain operations by delegating to children recursively.

WHY: The Composite is where the recursive power of the pattern lives. It implements the same interface as Leaf but does so by iterating over children and aggregating their results. This means operations like net_price() on a Cabinet automatically sum up all nested components — no client code has to know the tree depth or structure.

class CompositeComponent(Component):
    """A container node that can hold both Leaves and other Composites."""

    def __init__(self, name: str):
        self._name = name
        self._children: list[Component] = []

    def add(self, component: Component) -> None:
        self._children.append(component)

    def remove(self, component: Component) -> None:
        self._children.remove(component)

    def get_child(self, index: int) -> Optional[Component]:
        return self._children[index]

    def operation(self) -> str:
        results = [child.operation() for child in self._children]
        return f"Composite({self._name})[{', '.join(results)}]"

Equipment hierarchy — Composite with aggregation (GoF sample code):

class CompositeEquipment(Component):
    """Base for equipment that contains sub-equipment."""

    def __init__(self, name: str):
        self._name = name
        self._equipment: list[Component] = []

    def add(self, component: Component) -> None:
        self._equipment.append(component)

    def remove(self, component: Component) -> None:
        self._equipment.remove(component)

    def net_price(self) -> float:
        """Sum the net prices of all sub-equipment recursively."""
        # WHY: recursive delegation means Cabinet.net_price() automatically
        # traverses the full tree — no client code needs to walk the structure.
        return sum(child.net_price() for child in self._equipment)

class Chassis(CompositeEquipment):
    """A chassis holds drives, buses, and cards."""
    def __init__(self, name: str):
        super().__init__(name)
        self._wattage = 0

    def net_price(self) -> float:
        return super().net_price()   # inherits summation from CompositeEquipment

class Cabinet(CompositeEquipment):
    """A cabinet holds chassis and other equipment."""
    pass

# Assembly:
cabinet = Cabinet("PC Cabinet")
chassis = Chassis("PC Chassis")
cabinet.add(chassis)

bus = CompositeEquipment("MCA Bus")
bus.add(FloppyDisk("Token Ring Card", wattage=4, price=29.99))
chassis.add(bus)
chassis.add(FloppyDisk("3.5in Floppy", wattage=5, price=19.99))

print(cabinet.net_price())  # Recursively sums all sub-equipment prices

Step 5: Make the Safety-vs-Transparency Decision

ACTION: Decide where to declare child management operations (add, remove, get_child) — in Component (transparency) or only in Composite (safety). This is the central design decision of the Composite pattern.

WHY: This trade-off has no universally correct answer — it depends on what kind of errors your system must catch and at what point. Choosing transparency means clients never need to downcast or type-check, which is the core promise of the pattern. Choosing safety means misuse is caught at compile time, but clients that want to use the full Composite interface must check types at runtime. Consciously choose; do not let it default.

The trade-off:

OptionWhat it gives youWhat it costs you
Transparency — declare add/remove in ComponentClients treat all components uniformly; no downcasting neededLeaves inherit operations that are meaningless for them; add() on a Leaf must fail at runtime
Safety — declare add/remove only in CompositeMisuse caught at compile time (statically typed languages); Leaf interface is cleanClients must downcast to Composite to manage children; uniformity breaks

GoF recommendation: Emphasize transparency — declare child management in Component, implement defaults that fail at runtime. This preserves the pattern's central benefit.

Implementing safe transparency with get_composite() (GoF idiom):

If you choose safety but still want to avoid unsafe downcasts, add a get_composite() method to Component that returns None by default, and override it in Composite to return self. Clients use this to obtain the Composite interface safely:

class Component(ABC):
    def get_composite(self) -> Optional["CompositeComponent"]:
        """Returns self if this component is a Composite, None otherwise."""
        return None   # Default: not a composite

class CompositeComponent(Component):
    def get_composite(self) -> Optional["CompositeComponent"]:
        return self   # Override: I am a composite

# Safe usage — no blind downcast:
if composite := component.get_composite():
    composite.add(new_leaf)

When transparency raises on Leaf.add(): Make add() fail by raising an exception — not silently succeed. Silently ignoring add() on a leaf hides a bug (the caller believes the component was added). Raising makes misuse visible immediately.


Step 6: Apply Remaining Implementation Concerns

ACTION: Evaluate each of the 9 implementation concerns and apply the relevant ones to your design.

WHY: The 9 concerns are not all mandatory — they are a checklist of decisions that frequently arise. Each one you skip is an implicit default that may cause problems later (e.g., not managing parent references will complicate deletion; not addressing ordering will produce incorrect tree traversal). Work through the list deliberately, even if the answer is "not applicable."

See references/composite-implementation-guide.md for full details on each concern.

Checklist:

#ConcernDecision to make
1Explicit parent referencesDoes traversal upward (to parent) simplify your operations? If yes, add a parent field to Component and maintain it in add()/remove().
2Sharing componentsCan a node appear under two parents? If yes, apply Flyweight — externalize mutable state so nodes do not need to know their parent.
3Maximizing the Component interfaceHave you moved as many operations to Component as reasonable (with sensible leaf defaults)?
4Safety vs. transparencyDecided in Step 5. Confirm the choice is consistently applied.
5Child list storageDoes every Composite have the same child storage structure? If Composites vary significantly, store the child list in each Composite subclass rather than a shared base. Watch the memory cost of putting a list in every Leaf.
6Child orderingDoes the sequence of children matter (rendering order, parse tree structure)? If yes, use an ordered list and design add() to accept a position. Consider Iterator for traversal.
7CachingAre traversals expensive? Cache computed results (e.g., bounding boxes, aggregated prices) in Composite. Invalidate parent caches when a child changes — requires parent references (concern 1).
8Who deletes componentsIn languages without garbage collection: Composite is responsible for deleting its children on destruction, except when Leaf objects are immutable and shared (Flyweight).
9Data structure for childrenDefault is a list. Use a tree for sorted order, a hash table for fast lookup by key, or per-child named fields when the set of children is fixed and known.

Applying parent references (concern 1):

class Component(ABC):
    def __init__(self):
        self._parent: Optional["CompositeComponent"] = None

    @property
    def parent(self) -> Optional["CompositeComponent"]:
        return self._parent

class CompositeComponent(Component):
    def add(self, component: Component) -> None:
        self._children.append(component)
        component._parent = self    # maintain invariant: child's parent = this composite

    def remove(self, component: Component) -> None:
        self._children.remove(component)
        component._parent = None    # clear parent when removed

Step 7: Validate the Refactored Structure

ACTION: Verify the implementation is complete and uniform treatment holds end-to-end.

WHY: The refactoring is only successful if client code that operated on leaves or composites separately can now use the Component interface uniformly, without branching on type. If any client still does isinstance(node, Composite) for anything other than the explicit get_composite() safety idiom, the pattern is incomplete.

Validation checklist:

  • [ ] Client code uses only the Component interface for domain operations — no isinstance checks to decide which operation to call
  • [ ] operation() (or equivalent domain method) produces correct results on a Leaf, a shallow Composite, and a deep nested Composite
  • [ ] add() / remove() on a Leaf either raises a clear exception (safety) or fails with a meaningful error (transparency variant)
  • [ ] Adding a new Leaf type requires only a new class implementing Component — no changes to existing Composites or client code
  • [ ] Adding a new Composite type requires only a new class extending CompositeEquipment (or equivalent) — no changes to clients
  • [ ] If caching was added (concern 7), modifying a child correctly invalidates the parent's cache
  • [ ] If parent references were added (concern 1), the invariant holds: every child's parent points to its containing Composite

Examples

Example 1: File System Hierarchy

Scenario: A file system utility needs to calculate directory sizes. Currently, code special-cases directories vs. files with isinstance checks throughout the size calculation logic.

Trigger: "Every place we compute size or count files, we have to check whether we're dealing with a file or a directory."

Before (type-branching code smell):

def get_size(node):
    if isinstance(node, File):
        return node.size
    elif isinstance(node, Directory):
        return sum(get_size(child) for child in node.children)

After (Composite):

class FileSystemNode(ABC):
    @abstractmethod
    def size(self) -> int: ...
    def add(self, node: "FileSystemNode") -> None:
        raise NotImplementedError
    def get_children(self) -> list["FileSystemNode"]:
        return []

class File(FileSystemNode):
    def __init__(self, name: str, size_bytes: int):
        self._name = name
        self._size = size_bytes
    def size(self) -> int:
        return self._size

class Directory(FileSystemNode):
    def __init__(self, name: str):
        self._name = name
        self._children: list[FileSystemNode] = []
    def add(self, node: FileSystemNode) -> None:
        self._children.append(node)
    def get_children(self) -> list[FileSystemNode]:
        return self._children
    def size(self) -> int:
        return sum(child.size() for child in self._children)

# Client — no isinstance, no branching:
root = Directory("root")
root.add(File("readme.txt", 1024))
docs = Directory("docs")
docs.add(File("design.pdf", 204800))
root.add(docs)
print(root.size())  # 205824 — traverses entire tree automatically

Output: Client code calls node.size() uniformly. A new SymbolicLink type (a Leaf with a size pointing to its target) requires zero changes to directories or the size computation.


Example 2: UI Component Tree (React-style)

Scenario: A server-side UI renderer builds HTML from a component tree. Panels hold other components; buttons, labels, and inputs are leaves. The renderer must call render() on the root and get complete HTML.

Trigger: "We're adding more container types (tabs, accordions) and the render function keeps growing with new if isinstance(...) branches."

Design:

class UIComponent(ABC):
    @abstractmethod
    def render(self, indent: int = 0) -> str: ...
    def add(self, component: "UIComponent") -> None:
        raise NotImplementedError("Leaf UI components do not support add()")

class Button(UIComponent):
    def __init__(self, label: str):
        self._label = label
    def render(self, indent: int = 0) -> str:
        return " " * indent + f"<button>{self._label}</button>"

class Panel(UIComponent):
    def __init__(self, css_class: str):
        self._class = css_class
        self._children: list[UIComponent] = []
    def add(self, component: UIComponent) -> None:
        self._children.append(component)
    def render(self, indent: int = 0) -> str:
        inner = "\
".join(child.render(indent + 2) for child in self._children)
        return f'{" " * indent}<div class="{self._class}">\
{inner}\
{" " * indent}</div>'

# Assembly and rendering:
form = Panel("login-form")
form.add(Button("Sign In"))
form.add(Button("Cancel"))
page = Panel("page")
page.add(form)
print(page.render())  # Full recursive HTML, no type checks

Output: Adding a TabContainer composite or an Input leaf requires no changes to render() callers or existing components.


Example 3: Lexi Document Structure (GoF Case Study)

Scenario: Lexi is a WYSIWYG document editor. Documents are built from graphical elements: characters, images, and lines at the leaf level; rows and columns as composites. Operations like Draw(), Bounds(), and Intersects() must work on any element regardless of complexity — a single character and a multi-column page are treated identically by the rendering engine.

The Glyph hierarchy (GoF pages 43-48):

Component:  Glyph     — Draw(Window), Bounds(Rect), Intersects(Point), Insert(Glyph, int), Remove(Glyph), Child(int), Parent()
Leaf:       Character — holds a char, draws via w->DrawCharacter(c)
Leaf:       Rectangle — draws via w->DrawRect(x0, y0, x1, y1)
Leaf:       Image     — holds a bitmap, draws to window
Composite:  Row       — arranges children left-to-right; Draw() iterates children, ensures each is positioned, calls c->Draw(w)
Composite:  Column    — arranges Row children vertically

Key design decisions made in Lexi:

  1. Transparency chosen: Insert(), Remove(), and Child() are declared on Glyph (the Component), not just on Row (the Composite). Leaves do not override these — clients can always call them without type-checking.
  2. Parent references used: Glyph declares Parent(). Every glyph stores a reference to its parent so the formatter can walk up the structure and so Remove() can detach a glyph from its container.
  3. Ordered children: Row uses an ordered list for children — the sequence of characters defines the visual order on screen. Insert(Glyph* g, int i) inserts at a specific position.
  4. Operation maximization: Bounds() is defined on all Glyphs, not just containers. A Character's bounding box is its character cell; a Row's bounding box is the union of its children's bounding boxes.

Result: The formatter, spell-checker, and renderer all hold Glyph* references and call Draw(), Bounds(), or Intersects() uniformly — whether the target is a single character or a nested multi-column structure, the code is identical.


Key Principles

  • The pattern's value is uniform treatment — if clients still branch on leaf-vs-composite for domain operations, the pattern has failed. Every isinstance check for operational dispatch is a sign the Component interface needs expansion.
  • Transparency is a deliberate choice, not a default — declaring child management in Component trades compile-time safety for uniformity. Make this choice explicitly and document it. Do not let it happen because you copied a template.
  • Recursive delegation is the mechanism — a Composite's operation() should almost always iterate over children and aggregate. The power of the pattern is that cabinet.net_price() correctly sums a deeply nested tree without the caller knowing the depth or structure.
  • Leaves must still handle child management calls gracefully — whether by raising a clear exception (transparency + safety) or silently doing nothing (transparency only). Silent no-ops hide bugs; prefer raising with a message.
  • "Can make design overly general" is a real risk — the pattern makes it easy to add any component anywhere in the tree. If you want a Composite to hold only certain types of children, Composite cannot enforce that constraint via the type system — you must add runtime checks. Acknowledge this limitation explicitly; it may mean Composite is the wrong choice when type constraints are essential. Always ask: "Should ANY child be addable to ANY composite, or do structural rules apply?" If rules apply, add validation in add() and document which child types each Composite accepts.
  • Use Iterator for traversal, Visitor for operations — once you have a Composite tree, two companion patterns become relevant. Use Iterator when clients need to traverse the tree in different orders (preorder, postorder, breadth-first) without knowing the tree's internal structure. Use Visitor when you need to add new operations to the tree (validation, rendering, aggregation) without modifying the Component classes. Iterator + Visitor together are the standard way to operate on Composite structures — Iterator handles the "walk" and Visitor handles the "what to do at each node."

References

FileContents
references/composite-implementation-guide.mdAll 9 implementation concerns with full rationale, language-specific notes, related patterns (Chain of Responsibility, Flyweight, Iterator, Visitor, Decorator), and the complete GoF consequences catalog

License

This 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.

Related BookForge Skills

Install related skills from ClawhHub:

  • clawhub install bookforge-structural-pattern-selector

Or install the full book set from GitHub: bookforge-skills

平台分布

OpenClaw

78.66%
按下载量换算958

安全审计

VirusTotal

通过

ClawScan

通过

Static analysis

通过

权限和风险

调用外部服务

该 Skill 可能调用第三方服务、云服务或外部模型 API,使用前需要确认账号、额度、数据发送范围和服务条款。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills