显示页面讨论反向链接回到顶部 本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。 ====== C# 设计模式:组合模式 (Composite Pattern) ====== 组合模式(Composite Pattern)是一种**结构型设计模式**。它允许你将对象组合成**树形结构**来表现“整体/部分”的层次结构。组合能让客户端以一致的方式处理个别对象(叶子)和对象组合(容器)。 ===== 1. 核心概念 ===== 在 C# 中实现组合模式,主要涉及三个角色: * **Component (抽象构件)**: 这是一个接口或抽象类,为组合中的对象声明接口。它实现了所有类共有接口的默认行为。 * **Leaf (叶子节点)**: 在组合中表示叶子节点对象,叶子节点没有子节点。它实现了 Component 中的业务方法。 * **Composite (容器节点)**: 定义有子部件的那些部件的行为。它存储子部件,并实现在 Component 接口中定义的与子部件有关的操作(如 Add, Remove)。 ===== 2. 操作步骤与代码实现 ===== 我们以**“文件系统”**为例:文件夹(Composite)可以包含文件(Leaf),也可以包含其他文件夹。 ==== 第一步:定义抽象构件 (Component) ==== 这是所有对象的基类。为了保证“透明性”,我们通常在这里定义管理子节点的方法(Add/Remove),尽管叶子节点可能不需要它们。 <code csharp> using System; using System.Collections.Generic; namespace CompositePatternDemo { // 抽象构件 public abstract class FileSystemItem { protected string _name; public FileSystemItem(string name) { _name = name; } // 核心业务方法:所有节点都有这个功能 public abstract void Display(int depth); // 管理子节点的方法(虚方法,默认抛出异常,由容器节点重写) // 这种方式称为“透明方式”,客户端不需要区分是叶子还是容器 public virtual void Add(FileSystemItem item) { throw new NotImplementedException("叶子节点不支持添加子项"); } public virtual void Remove(FileSystemItem item) { throw new NotImplementedException("叶子节点不支持移除子项"); } } } </code> ==== 第二步:定义叶子节点 (Leaf) ==== 叶子节点代表具体的实体(如文件)。它**不包含**子节点列表。 <code csharp> namespace CompositePatternDemo { // 叶子节点:文件 public class File : FileSystemItem { public File(string name) : base(name) { } public override void Display(int depth) { // 通过连字符显示层级深度 Console.WriteLine(new String('-', depth) + " File: " + _name); } // File 不需要重写 Add 和 Remove,因为继承的默认行为是抛出异常,符合逻辑 } } </code> ==== 第三步:定义容器节点 (Composite) ==== 容器节点包含一个子节点列表,并实现了管理子节点的方法。**关键点在于它的业务方法通常会递归调用子节点的业务方法。** <code csharp> namespace CompositePatternDemo { // 容器节点:文件夹 public class Directory : FileSystemItem { // 内部维护一个子组件列表 private List<FileSystemItem> _children = new List<FileSystemItem>(); public Directory(string name) : base(name) { } // 重写 Add 方法 public override void Add(FileSystemItem item) { _children.Add(item); } // 重写 Remove 方法 public override void Remove(FileSystemItem item) { _children.Remove(item); } // 核心:递归调用 public override void Display(int depth) { // 1. 显示自己 Console.WriteLine(new String('-', depth) + " Directory: " + _name); // 2. 遍历并显示所有子节点(递归) foreach (var component in _children) { component.Display(depth + 2); } } } } </code> ==== 第四步:客户端调用 ==== 客户端代码不需要关心它处理的是简单的 `File` 还是复杂的 `Directory`,它只需要针对 `FileSystemItem` 编程。 <code csharp> class Program { static void Main(string[] args) { // 1. 创建根节点 Directory root = new Directory("Root"); // 2. 创建叶子节点 File file1 = new File("Config.xml"); File file2 = new File("Logo.png"); // 3. 创建子容器 Directory subDir = new Directory("Bin"); File subFile = new File("App.exe"); // 4. 组装树形结构 root.Add(file1); root.Add(file2); subDir.Add(subFile); // 向子文件夹添加文件 root.Add(subDir); // 将子文件夹添加到根目录 // 5. 操作整体 // 客户端只需要调用根节点的 Display,整个树结构会自动递归处理 Console.WriteLine("文件系统结构图:"); root.Display(1); } } </code> ===== 3. 两种实现方式的权衡:透明 vs 安全 ===== 在 C# 实现中,关于 `Add` 和 `Remove` 方法放在哪里,有两种流派: - **透明方式 (Transparency)**: - **操作**: 如上例所示,在抽象类 `Component` 中声明 `Add`/`Remove`。 - **优点**: 客户端不需要区分是叶子还是容器,调用一致。 - **缺点**: 叶子节点调用 `Add` 会在运行时报错(不够安全)。 - **安全方式 (Safety)**: - **操作**: 在 `Component` 中**不**声明 `Add`/`Remove`,只在 `Composite` 类中声明。 - **优点**: 编译期就能检查错误,叶子节点根本没有 `Add` 方法。 - **缺点**: 客户端必须区分对待,如果想添加子节点,必须先将对象强制转换为 `Composite` 类型。 ===== 4. 适用场景 ===== * **BIM 开发**: 如“筏板(Raft)”包含“电梯井(Pit)”,“楼层”包含“墙/柱/梁”。 * **UI 控件树**: WinForms 或 WPF 中,Panel 可以包含 Button,也可以包含其他 Panel。 * **图形编辑器**: 一个“分组”可以包含圆形、矩形,也可以包含另一个“分组”。 ===== 5. 总结 ===== 组合模式的核心在于利用**多态**和**递归**。通过将容器和叶子抽象为同一类型,使得极其复杂的树形结构在客户端看来只是一个简单的对象。 登录 Detach Close 该主题尚不存在 您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。 csharp/gof23种设计模式/组合模式.txt 最后更改: 2026/01/09 12:33由 张叶安 登录