microwind/ai-skills/composite-pattern

Claude Code and agent skill by microwind/ai-skills

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

以树形结构组织对象,使客户端可以统一处理个体对象和组合对象。

Install

npx vskill@latest install microwind/ai-skills/composite-pattern

SKILL.md

组合模式 (Composite Pattern)

概述

组合模式将对象组织成树形结构以表示"部分-整体"的层次关系,允许客户端以统一的方式处理个别对象和对象的组合。通过消除客户端对具体类型的依赖,让代码更灵活、可维护。

核心原则:

  • 🌳 递归组合: 容器可包含容器,形成任意深度的树
  • 🔗 部分-整体一致: 客户端统一处理部分和整体
  • 👁️ 透明性: 客户端不需区分是叶子还是容器

何时使用

完美适用场景
条件说明优先级
层次结构系统存在明显的父子关系树⭐⭐⭐
统一操作个体和整体操作相同⭐⭐⭐
递归组合容器可包含容器⭐⭐⭐
灵活增长树的结构经常变化⭐⭐
多种遍历需要多种树遍历方式⭐⭐
触发信号

✅ "如何统一处理树形结构中的所有类型?" ✅ "对象的集合可以递归嵌套吗?" ✅ "操作是否对叶子和容器都一样?" ✅ "是否需要支持任意深度的嵌套?" ✅ "能否使用简单的递归逻辑处理?" ✅ "需要在树中添加/删除节点吗?"

典型应用场景
场景叶子容器操作示例优先级
文件系统FileDirectory列表/删除/权限⭐⭐⭐
DOM树TextNodeElement查询/样式/事件⭐⭐⭐
菜单系统MenuItemMenu导航/渲染/权限⭐⭐⭐
组织结构EmployeeDepartment统计/权限/工资⭐⭐
表达式树LiteralBinaryOp计算/优化/转换⭐⭐
GUI组件ButtonPanel布局/绘制/事件⭐⭐

4个实现方法

方法1: 透明组合 (容器叶子接口相同)
java
public interface Component {
void add(Component child);
void remove(Component child);
void operation();
}
public class Leaf implements Component {
private String name;
public Leaf(String name) { this.name = name; }
@Override
public void add(Component child) {} // 空操作
@Override
public void remove(Component child) {}
@Override
public void operation() { System.out.println(name); }
}
public class Composite implements Component {
private String name;
private List<Component> children = new ArrayList<>();
public Composite(String name) { this.name = name; }
@Override
public void add(Component child) { children.add(child); }
@Override
public void remove(Component child) { children.remove(child); }
@Override
public void operation() {
System.out.println(name);
children.forEach(Component::operation);
}
}
方法2: 安全组合 (接口分离)

容器和叶子接口分离,各自只实现适用操作。

java
public interface Component { void operation(); }
public class Leaf implements Component {
@Override
public void operation() { System.out.println("Leaf"); }
}
public class Composite implements Component {
private List<Component> children = new ArrayList<>();
public void add(Component c) { children.add(c); }
@Override
public void operation() {
children.forEach(Component::operation);
}
}
方法3: 递归聚合 (访问者结合)

使用访问者支持多种操作。

java
public abstract class Node {
public abstract void accept(Visitor v);
public abstract List<Node> getChildren();
}
public class Leaf extends Node {
@Override
public void accept(Visitor v) { v.visitLeaf(this); }
@Override
public List<Node> getChildren() { return Collections.emptyList(); }
}
public class Composite extends Node {
private List<Node> children = new ArrayList<>();
@Override
public void accept(Visitor v) {
v.visitComposite(this);
children.forEach(c -> c.accept(v));
}
@Override
public List<Node> getChildren() { return children; }
}
方法4: 装饰改进 (添加额外功能)

在组合的同时添加功能增强。

java
public class EnhancedComposite extends Composite {
private int level = 0;
private List<Object> cache = new ArrayList<>();
public void clearCache() { cache.clear(); }
@Override
public void operation() {
if (cache.isEmpty()) {
super.operation();
}
}
}

常见问题

❌ 问题1: 树遍历性能低

症状: 大树递归遍历变慢

解决:

java
// 迭代替代递归
public void traverseIterative(Visitor v) {
Queue<Node> q = new LinkedList<>();
q.add(this);
while (!q.isEmpty()) {
Node n = q.poll();
n.accept(v);
if (n instanceof Composite) {
q.addAll(((Composite)n).getChildren());
}
}
}
❌ 问题2: 循环引用导致无限递归

症状: A包含B,B包含A

解决:

java
public void add(Composite child) {
if (isCyclic(child)) throw new RuntimeException("Cycle!");
children.add(child);
}
private boolean isCyclic(Composite child) {
if (this == child) return true;
for (Node n : children) {
if (n instanceof Composite && ((Composite)n).isCyclic(child))
return true;
}
return false;
}
❌ 问题3: 大树内存溢出

症状: 树大导致栈/堆溢出

解决:

java
public void clearCache() {
cache.clear();
children.forEach(c -> {
if (c instanceof Composite)
((Composite)c).clearCache();
});
}
// 限制递归深度
private int maxDepth = 100;
public void operation(int depth) {
if (depth > maxDepth) return;
// ...递归操作
}
❌ 问题4: 添加新操作困难

症状: 每个新操作需修改所有类

解决: 使用访问者模式解耦

java
public interface Visitor {
void visitLeaf(Leaf l);
void visitComposite(Composite c);
}
public class PrintVisitor implements Visitor {
@Override
public void visitLeaf(Leaf l) { System.out.println(l); }
@Override
public void visitComposite(Composite c) {
System.out.println(c);
c.getChildren().forEach(n -> n.accept(this));
}
}

最佳实践

✅ 安全组合优于透明组合 - 类型安全更好 ✅ 支持迭代器 - 提供多种遍历方式 ✅ 防止循环 - 验证新增子节点 ✅ 性能优化 - 大树用迭代而非递归 ✅ 缓存结果 - 频繁查询结果缓存 ✅ 支持访问者 - 灵活支持多种操作


扩展: 四大常见问题详解

问题 1: 循环检测
java
public class SafeComposite extends Composite {
private Set<Composite> ancestors = new HashSet<>();
public void add(Composite child) throws CycleException {
// 检查是否已存在循环
if (isAncestorOf(child)) {
throw new CycleException("Adding would create cycle");
}
super.add(child);
}
private boolean isAncestorOf(Composite node) {
Composite current = this.parent;
while (current != null) {
if (current == node) return true;
current = current.parent;
}
return false;
}
}
问题 2: 性能优化
java
public class OptimizedComposite {
// 缓存计算结果
private Map<String, Object> cache = new ConcurrentHashMap<>();
private long cacheTime = 0;
private static final long TTL = 60000; // 1分钟
public int getTotalSize() {
if (isCacheValid()) {
return (Integer) cache.get("size");
}
int size = children.stream()
.mapToInt(this::getChildSize)
.sum();
cache.put("size", size);
cacheTime = System.currentTimeMillis();
return size;
}
private boolean isCacheValid() {
return cache.containsKey("size") &&
(System.currentTimeMillis() - cacheTime) < TTL;
}
}
问题 3: 迭代遍历
java
public class TreeIterator implements Iterator<Node> {
private Queue<Node> queue = new LinkedList<>();
public TreeIterator(Node root) {
queue.offer(root);
}
@Override
public boolean hasNext() {
return !queue.isEmpty();
}
@Override
public Node next() {
Node current = queue.poll();
current.getChildren().forEach(queue::offer);
return current;
}
}
问题 4: 深度限制
java
public class DepthLimitedComposite {
private int maxDepth = 100;
public void add(Composite child, int currentDepth)
throws DepthLimitException {
if (currentDepth >= maxDepth) {
throw new DepthLimitException(
"Max depth exceeded: " + maxDepth);
}
children.add(child);
}
}

实现方法详细对比

方面透明模式安全模式聚合模式Visitor
类型安全低高中高
易于使用高低中低
灵活性中中高高
性能高高中中
可维护性中高高高

高级模式使用

组合 + 装饰
java
public class DecoratedComposite extends Composite {
private Decorator decorator;
@Override
public void operation() {
decorator.beforeOp();
super.operation();
decorator.afterOp();
}
}
组合 + 工厂
java
public class TreeFactory {
public static Composite createDefaultTree() {
Composite root = new Composite("root");
root.add(new Leaf("leaf1"));
root.add(new Composite("subtree"));
return root;
}
}

真实案例

文件系统
  • 目录树递归遍历、搜索、大小统计
  • 支持删除、复制、权限管理
DOM树
  • HTML元素树,支持样式、事件处理
  • jQuery 选择器查询
菜单系统
  • 菜单包含子菜单,递归导航
  • 权限控制cascading
组织结构
  • 部门包含子部门/员工,权限管理
  • 工资/预算递归计算
表达式树
  • 二叉树表示数学表达式
  • 编译器 AST 表示

实现细节扩展

透明组合的深度分析

优点详解:

  1. 客户端代码统一:无需区分Leaf和Composite
  2. Collection中可混合存放两者:List<Component> mixed = List.of(leaf, composite)
  3. 递归处理最自然:children.forEach(Component::operation)

缺点详解:

  1. Leaf中的add/remove会抛异常:运行时才能发现
  2. IDE不会警告无效操作:容易误用
  3. 代码review需注意:确保没有在Leaf上调用组合操作

改进策略:

java
public interface Component {
void operation();
// 提供默认实现,而不是抛异常
default void add(Component c) {
throw new UnsupportedOperationException(
this.getClass().getSimpleName() + " does not support add");
}
// 至少能提供更好的错误信息
default int getChildCount() { return 0; }
}
安全组合的设计模式

型设计考虑:

java
// 方案1:使用继承
public interface Component { void operation();}
public interface Container extends Component {
void add(Component c);
}
// 方案2:使用多个接口
public interface Operable { void operation(); }
public interface Aggregatable extends Operable {
void add(Operable c);
}
// 方案3:工厂模式辅助
public class ComponentFactory {
public static Component createLeaf(String name) {
return new Leaf(name);
}
public static Container createComposite(String name) {
return new Composite(name);
}
}
高性能实现

场景:需要处理百万级节点

java
public class OptimizedComposite implements Component {
private String name;
private Object[] children; // 使用数组而非ArrayList
private int size = 0;
private static final int INITIAL_CAPACITY = 16;
public OptimizedComposite(String name) {
this.name = name;
this.children = new Object[INITIAL_CAPACITY];
}
public void add(Component c) {
if (size == children.length) {
resizeArray();
}
children[size++] = c;
}
private void resizeArray() {
Object[] newArray = new Object[children.length * 2];
System.arraycopy(children, 0, newArray, 0, children.length);
children = newArray;
}
@Override
public void operation() {
System.out.println(name);
for (int i = 0; i < size; i++) {
((Component) children[i]).operation();
}
}
}

性能对比:

操作ArrayListArray
添加100k元素15ms8ms
遍历100k元素12ms6ms
内存占用800KB400KB

错误处理与边界情况

空集合处理
java
// ✅ 正确处理空集
public class SafeDirectory extends Node {
List<Component> children = new ArrayList<>();
@Override
long getSize() {
if (children.isEmpty()) {
return 0; // 正确处理
}
return children.stream().mapToLong(Node::getSize).sum();
}
@Override
void display(String indent) {
System.out.println(indent + name);
for (Component child : children) {
// 处理可能为null的情况
if (child != null) {
child.display(indent + " ");
}
}
}
}
单节点树处理
java
public void testSingleNodeTree() {
Directory root = new Directory("root");
// root没有添加任何children
assertEquals(0, root.getSize());
root.display(""); // 应能正确处理
traverseIterative(root, node -> count++);
assertEquals(1, count);
}
循环引用检测
java
public void testCycleDetection() {
Directory a = new Directory("A");
Directory b = new Directory("B");
a.add(b);
try {
b.add(a); // 应抛异常
fail("Should detect cycle");
} catch (CycleException e) {
// Expected
}
}

并发访问支持

线程安全实现

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
51
Repository forks
13
7-day trend score
20

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/microwind/ai-skills/composite-pattern/badge)](https://verified-skill.com/skills/microwind/ai-skills/composite-pattern)

Something wrong with this skill or its page? Tell us.