详解:用统一接口构建树形对象层次结构)
教程知识库【免费下载链接】tech-interview-for-developer 신입 개발자 전공 지식 기술 면접 백과사전 项目地址https://gitcode.com/GitHub_Trending/te/tech-interview-for-developer点击查看免费下载导读本文基于tech-interview-for-developer仓库中 Composite Pattern.md 一文系统讲解 GoF 结构型设计模式中的组合模式Composite Pattern如何用同一个抽象接口Component统一管理叶子对象Leaf与容器对象Composite从而把对象组织成树形层次结构hierarchy并让调用方无需区分单个对象还是对象组合就能以完全一致的方式递归处理它们。读完本文你将掌握组合模式的核心类结构、透明性Transparency与安全性Safety两种实现取舍以及它与 Decorator、Iterator 等模式的关联并看到可直接运行的 Java 参考实现。一、组合模式要解决什么问题在现实系统中我们经常遇到部分-整体的层次结构文件系统中的文件夹里既可以放文件也可以继续放子文件夹GUI 中的容器组件里既可以放按钮也可以嵌套其他容器菜单系统中菜单里既有菜单项也可以嵌套子菜单。如果分别用文件类和文件夹类、按钮类和容器类来处理调用方就必须在代码里不断用if判断当前对象是叶子还是容器导致客户端逻辑与具体的对象类型强耦合。组合模式的核心目的是表达对象的层次结构hierarchies并让每个对象都能通过同一个接口被独立、一致地处理。这正是原文档开篇点明的意图——让Leaf类和Composite类共用同一个接口客户端只需面向统一的Component抽象编程无需关心自己正在操作的是单个对象还是一个对象集合。在 GoF 分类中组合模式属于结构型Structural模式它关心的正是对象间关系的组织。仓库的 Design Pattern Overview 中把结构型模式概括为组织对象间的关系组合模式正是这一思想在树形结构上的典型体现。二、类图与核心角色原文档给出了组合模式的经典类图仓库图片 composite_pattern_1.PNG从类图可以看出四个核心角色角色类职责抽象构件Component定义组合中所有对象的统一接口包括业务操作operation()以及子节点管理方法add / remove / getChild叶子构件Leaf组合中的最小原子单元没有子节点只实现operation()组合构件Composite可包含子构件叶子或其他组合实现operation()并递归调用所有子节点的操作同时实现子节点的增删查客户端Client只依赖抽象Component无需区分叶子与组合类图中Leaf与Composite都通过泛化继承关系指向抽象的ComponentClient仅单向依赖Component的公共接口从而实现多态调用。为了把叶子和容器统一进同一个接口抽象Component类中同时声明了业务操作与子节点管理操作两组方法——这正是组合模式与普通树结构实现的本质区别。三、Java 参考实现原文档给出了可直接运行的 Java 骨架代码下面结合实现细节逐类展开。3.1 Component统一抽象构件public class Component { public void operation() { throw new UnsupportedOperationException(); } public void add(Component component) { throw new UnsupportedOperationException(); } public void remove(Component component) { throw new UnsupportedOperationException(); } public Component getChild(int i) { throw new UnsupportedOperationException(); } }关键设计点所有方法默认都抛出UnsupportedOperationException这是默认实现 子类选择性覆写的手法Leaf不需要子节点管理能力因此它可以不覆写add / remove / getChild一旦被误调用会在运行时得到明确异常提示Composite则会覆写全部方法真正实现子节点管理。这种默认抛异常、需要才覆写的做法让基类既提供了统一接口又不强制叶子类实现无意义的空方法是一种务实的折中。3.2 Leaf叶子构件public class Leaf extends Component { String name; public Leaf(String name) { this.name name; } public void operation() { // .. something ... // 例如打印自己的名称 System.out.println(Leaf: name); } }Leaf只覆写operation()不实现add / remove / getChild。它是层次结构中的终点代表不可再分解的最小对象。3.3 Composite组合构件public class Composite extends Component { ArrayList components new ArrayList(); String name; public Composite(String name) { this.name name; } public void operation() { Iterator iter components.iterator(); while (iter.hasNext()) { Component component (Component) iter.next(); component.operation(); } } public void add(Component component) { components.add(component); } public void remove(Component component) { components.remove(component); } public Component getChild(int i) { return (Component) components.get(i); } }Composite是组合模式递归能力的核心内部用ArrayList持有子构件列表operation()遍历components对每个子构件调用其operation()——由于子构件可能是Leaf也可能是另一个Composite因此一个方法调用会在整棵树上递归展开直到所有叶子都被处理add / remove / getChild实现对子节点集合的增、删、查操作。从实现角度看Composite.operation()中体现的自身操作 递归遍历子节点模式是组合模式最典型的行为特征。3.4 客户端统一调用示例public class Client { public static void main(String[] args) { Component root new Composite(root); Component branch1 new Composite(branch1); branch1.add(new Leaf(leaf1)); branch1.add(new Leaf(leaf2)); Component branch2 new Composite(branch2); branch2.add(new Leaf(leaf3)); root.add(branch1); root.add(branch2); // 无需区分 Leaf 还是 Composite统一调用 root.operation(); } }调用方持有的引用类型始终是Component无论对象是叶子还是容器都只调用operation()完全符合组合模式统一接口、透明调用的设计目标。四、实现时必须考虑的两个设计问题原文档在实现时需要考虑的事项一节中明确提出了两个在编码前必须回答的问题这两点也是面试与架构设计中的高频考点。4.1 子节点是否要反向引用父节点基础实现中只有 parent 持有 child 的引用单向关系。但在某些场景下子节点需要回溯到父节点删除一个节点时需要先找到它的父节点从父节点的子列表中去掉它向上遍历路径例如文件系统返回上级目录。如果不需要这些能力保持单向引用即可结构更简单、耦合更低如果需要则在节点中额外维护parent引用并处理好父子引用的同步维护新增/删除子节点时同时修正父指针。类图 composite_pattern_2.PNG 展示了包含1 parent双向关联的扩展形态即每个组合构件关联唯一父构件用于支持树形结构中的父节点回溯。4.2 由哪个类负责管理 childrenchildren 由谁管理直接决定了下面要讲的透明性与安全性两种实现变体是把add / remove / getChild放在抽象Component中所有节点对外接口一致还是只放在Composite中叶子不暴露管理能力。两种方案各有取舍详见下一节。五、Children 管理的两种实现变体Transparency 与 Safety原文档给出了组合模式的两大经典分支对应两张类图。5.1 Transparency透明性方案第一种方案即上文 3.1 的Component代码把add / remove / getChild声明在抽象Component类中从而向客户端提供Transparency透明性优点客户端无需区分Leaf与Composite一律当作Component使用接口完全统一客户端代码最简洁缺点Leaf本质上没有子节点一旦客户端对Leaf调用了add / remove / getChild就会在**运行时runtime**抛出UnsupportedOperationException错误被推迟到运行期才暴露。5.2 Safety安全性方案第二种方案中子节点管理方法add / remove / getChild只在Composite类中声明抽象Component仅保留业务接口operation()提供Safety安全性优点Leaf根本不具备子节点管理方法客户端若对Leaf调用这些方法会在**编译期compile time**就被编译器拦截错误发现得更早缺点客户端必须区分Leaf与Composite两种类型例如先用instanceof判断再强转才能调用子节点管理方法接口统一性有所牺牲客户端代码变得更复杂。5.3 两种方案如何取舍维度Transparency透明性Safety安全性管理方法声明位置抽象Component具体Composite客户端能否统一处理能完全透明需区分叶子与容器叶子被误调用管理方法运行时抛异常编译期报错接口一致性高低类型安全性低高实际项目中透明性方案更常见客户端代码干净但要注意对Leaf误操作的防御安全性方案则在类型安全要求严格的场景更受青睐。原文档对此的结论是透明性换来客户端统一性安全性换来编译期类型保障二者不可兼得需按项目实际约束选择。六、组合模式的真实应用场景嵌套菜单组合模式最经典的实战案例之一就是菜单嵌套菜单。仓库图片 composite_pattern_3.PNG 展示了这一实例在该实例中组合构件CompositeAll Menus顶层总容器、PancakeHouseMenu、DinerMenu、Café Menu、Dessert Menu嵌套在 Diner Menu 内部——它们既能包含菜单项也能继续包含子菜单形成树形嵌套叶子构件LeafMenuItem菜单项是最小单元没有下属节点统一操作打印菜单时只要对最外层All Menus调用一次打印操作就会递归地把所有子菜单与菜单项全部打印出来——这正是Composite.operation()递归遍历在真实业务中的直观体现。这个场景可以推广到几乎所有树形 UI文件资源管理器、组织结构图、绘图编辑器中的图形分组、HTML 文档对象树DOM等都是组合模式的用武之地。七、与相关模式的关联原文档在相关模式一节对比了组合模式与两个常见模式的异同这也是设计模式面试中的常问点。7.1 Composite 与 Decorator装饰器模式共同点二者都依赖**递归组合composition**来构造对象差异Decorator 的目标是动态地给对象附加责任responsibilities通过一层层包装增强功能而Composite 的目标是表达对象间的层次结构hierarchy让部分与整体被一致对待。仓库中的 Design Pattern Overview 将结构型模式定位为组织对象间的关系Decorator 与 Composite 恰好是这一类别下方向不同的两个代表一个横向包装、一个纵向分层。7.2 Composite 与 Iterator迭代器模式共同点二者都会顺序访问聚合对象aggregate object差异Iterator 关注如何按顺序遍历聚合对象这一访问机制而 Composite 关注如何组织对象的层次关系。二者常被组合使用——事实上上文Composite.operation()的参考实现里就使用了Iterator遍历子节点集合这正是两种模式协同的例证。仓库的 Observer pattern.md 中同样用Iterator增强 for 循环遍历观察者列表可以看到迭代器作为遍历聚合对象的标准工具在多个模式中的通用性。八、要点总结本质组合模式用统一的Component抽象把叶子对象与容器对象组织成树形层次结构让客户端以一致接口递归处理部分与整体。递归是灵魂Composite.operation()遍历子节点并继续调用operation()使一次调用沿树形结构自动扩散到全部叶子。默认抛异常Component中add / remove / getChild默认抛出UnsupportedOperationException子类按需覆写。两种变体Transparency管理方法放Component客户端统一但叶子误用会运行时异常与 Safety管理方法只放Composite编译期更安全但客户端需区分类型需结合类型安全与接口一致性权衡。设计前置问题实现前先确定是否需要子节点回溯父节点、以及 children 由谁管理。相关模式与 Decorator 同用递归组合但目标不同与 Iterator 常协同使用Iterator 负责遍历聚合对象。组合模式非常适合整体-部分递归结构的建模正确使用时能极大简化客户端代码但也要避免在层次关系不明显的场景中生搬硬套——正如仓库 Design Pattern Overview 所提醒的设计模式是想法而非固定实现应服务于复用、兼容与可维护性的目标。赞分享教程知识库【免费下载链接】tech-interview-for-developer 신입 개발자 전공 지식 기술 면접 백과사전 项目地址https://gitcode.com/GitHub_Trending/te/tech-interview-for-developer点击查看免费下载相关推荐组合模式Composite详解用树形结构统一整体/部分层次CS-Notes 设计模式系列组合模式Composite详解用树形结构统一整体/部分层次CS Notes 设计模式系列 组合模式Composite是结构型设计模式中的一员知识库文档教程lm-evaluation-harness 评测指南用 EleutherAI 基准测试框架系统评估 LLM 质量lm evaluation harness 评测指南用 EleutherAI 基准测试框架系统评估 LLM 质量 导读 本指南以仓库中 lm evaluatiAI 技能人工智能大模型深度学习DesignPatternsPHP 组合模式Composite PatternPHP 8 实现详解用一棵对象树统一渲染表单DesignPatternsPHP 组合模式Composite PatternPHP 8 实现详解用一棵对象树统一渲染表单 组合模式Composite示例工程教程上一篇Lucide 图标无障碍实践Vue 篇从默认 aria-hidden 到可访问的图标按钮下一篇Salt progress 输出器深度解析用 --progress 实时跟踪大规模 minion 返回进度创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考