在组合模式的Unity示例中, 核心遵循了一些设计原则, 但也因模式特性的存在对某一原则的”妥协”(并非结对违反, 而是为了模式目标的合理取舍).
 

一、遵循的设计原则

  1. 单一职责原则(SRP)
体现:叶子节点和复合节点各自承担单一职责。
  • 叶子节点(如 UIButton \ UIText )仅负责自身的基础行为 (显示\隐藏), 不关心子元素管理(因为它们没有子元素)
  • 复合节点(如 UIPanel ) 除了自身的显示\隐藏, 还负责子元素的管理(添加\移除\递归操作子节点), 职责聚焦于 “组合管理”.
 
两者职责边界清晰, 修改叶子节点的显示逻辑不会影响复合节点的子元素管理,反之亦然.
 
  1. 开放 - 封闭原则(OCP)
体现: 系统对扩展开放, 对修改封闭
  • 新增叶子节点(如 UIIcon 图标): 只需继承 UIComponent 并实现 Show / Hide , 无需修改现有 UIButton \ UIPanel 等代码.
  • 新增复合节点(如 UIScrollPanel 滚动面板): 只需继承 UIComponent , 重写自元素管理方法和递归逻辑, 现有代码无需改动.
  • 客户端(如 UIManager ) 调用的是抽象 UIComponent 接口, 新增元素后客户端代码无需修改.
 
  1. 依赖倒置原则(DIP)
体现: 客户端依赖抽象, 而非具体实现.
  • 客户端 UIComponent.Show() / Hide() 统一调用, 无需关心具体类型.这种依赖抽象的设计,让客户端与具体元素解耦,支持任意扩展.
 

二、因模式特性”妥协”的设计原则(非绝对违反)

组合模式的核心是”让叶子和复合节点对外暴露统一接口”, 这回导致对接口隔离原则(ISP)的一定程度的”违背“ (或称为“必要妥协”)
 
接口隔离原则(ISP)的核心思想:
客户端不应该依赖他不需要的接口; 一个类对另一个类的依赖应建立在最小的接口上.
 
组合模式中的”妥协”:
在示例中, 抽象组件 UIComponent 定义了所有方法, 包括叶子节点不需要的子元素管理方法 (AddChild \ RemoveChild 等).
  • 叶子节点(如 UIbutton )不需要管理子元素, 但为了实现 UIComponent 接口, 必须空实现这些方法(否则会有报错).
  • 这导致叶子节点依赖了自身不需要的接口方法, 一定程度上违反了”最小接口依赖”的原则
 
为什么是”必要妥协”?
组合模式的核心价值是”统一处理叶子和复合节点”. 如果为叶子和复合节点分别定义接口(如 ILeafIComposite ), 客户端就需要区分两种接口, 无法实现”统一操作”的目标.
 
因此, 这种对接口隔离原则的妥协, 是为了换取”树形结构统一处理”的核心又是, 属于模式设计中的合理取舍.
 
总结
组合模式主要遵循单一职责原则(分离叶子与复合节点的职责)\ 开放-封闭原则(支持独立扩展)\ 依赖导致原则(客户端依赖抽象); 但为了实现”统一接口”的核心目标, 会对接口隔离原则做出必要妥协(叶子节点被迫实现不需要的方法). 这种妥协是模式设计的权衡结果, 而非错误.