下面我将详细讲解“C# 设计模式系列教程-组合模式”的完整攻略。
什么是组合模式
组合模式是一种结构型设计模式,旨在将多个对象合成树形结构以表示具有“整体-部分”关系的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
其中,组合模式将“组合对象”和“叶子对象”抽象为一个共同的接口。这样,用户就可以统一地操作组合对象和叶子对象。
组合模式的应用场景
组合模式通常用于树形结构中。在这种情况下,单个对象和组合对象具有相同的基类或接口,并且可以嵌套使用。
下面是一些应用组合模式的经典场景:
- Windows 中的 UI 界面就是以树形结构组织的。
- 目录和文件系统可以使用组合模式实现。
- 人员和部门管理的组织结构图也可以使用组合模式实现。
组合模式的结构和角色
组合模式由以下角色构成:
- 抽象组件(Component):它是一个抽象类或接口,定义了组合对象的通用行为,包括添加、删除、获取子对象等操作。
- 叶子节点(Leaf):它表示组合中的叶子对象,它没有子对象。
- 组合节点(Composite):它表示组合中的组合对象,具有子对象。
- 客户端(Client):通过使用组合模式,可以统一对组合对象和叶子对象进行操作,客户端可以针对抽象组件编程,无需知道具体的实现类。
下面是组合模式的 UML 结构图:
+------+ +------+
|Component | | Component |
+------+ +------+
/ \ / \
/ \ / \
+-------+ +--------+ +-------+
| Leaf | | Composite | | Leaf |
+-------+ +----------+ +-------+
组合模式的示例代码
下面是一些使用组合模式的示例代码。
示例1:使用组合模式实现菜单
using System;
using System.Collections.Generic;
namespace CompositePattern
{
// 抽象组件:菜单项
public abstract class MenuItem
{
public string Name { get; set; }
public MenuItem(string name) => Name = name;
public abstract void AddChild(MenuItem child);
public abstract void RemoveChild(MenuItem child);
public abstract void Render(int depth);
}
// 叶子节点:菜单项
public class MenuItemLeaf : MenuItem
{
public MenuItemLeaf(string name) : base(name) { }
public override void AddChild(MenuItem child) => Console.WriteLine("叶子节点不能添加子节点");
public override void RemoveChild(MenuItem child) => Console.WriteLine("叶子节点没有子节点可以删除");
public override void Render(int depth)
{
Console.WriteLine(new string('-', depth) + Name);
}
}
// 组合节点:菜单项
public class MenuItemComposite : MenuItem
{
private List<MenuItem> children = new List<MenuItem>();
public MenuItemComposite(string name) : base(name) { }
public override void AddChild(MenuItem child) => children.Add(child);
public override void RemoveChild(MenuItem child) => children.Remove(child);
public override void Render(int depth)
{
Console.WriteLine(new string('-', depth) + Name);
foreach (var child in children)
child.Render(depth + 2);
}
}
// 客户端:菜单
public class Menu
{
public MenuItem MainItem = new MenuItemComposite("主菜单");
public void Render()
{
MainItem.Render(0);
}
}
class Program
{
static void Main(string[] args)
{
var menu = new Menu();
var fileMenu = new MenuItemComposite("文件菜单");
fileMenu.AddChild(new MenuItemLeaf("新建"));
fileMenu.AddChild(new MenuItemLeaf("打开"));
fileMenu.AddChild(new MenuItemLeaf("保存"));
var editMenu = new MenuItemComposite("编辑菜单");
editMenu.AddChild(new MenuItemLeaf("复制"));
editMenu.AddChild(new MenuItemLeaf("粘贴"));
editMenu.AddChild(new MenuItemLeaf("剪切"));
menu.MainItem.AddChild(fileMenu);
menu.MainItem.AddChild(editMenu);
menu.Render();
}
}
}
示例2:使用组合模式实现文件系统
using System;
using System.Collections.Generic;
namespace CompositePattern
{
// 抽象组件:文件系统的元素
public abstract class FileSystemElement
{
public string Name { get; set; }
public FileSystemElement(string name) => Name = name;
public abstract void AddChild(FileSystemElement child);
public abstract void RemoveChild(FileSystemElement child);
public abstract void Render(int depth);
}
// 叶子节点:文件
public class File : FileSystemElement
{
public File(string name) : base(name) { }
public override void AddChild(FileSystemElement child) => Console.WriteLine("文件不能添加子元素");
public override void RemoveChild(FileSystemElement child) => Console.WriteLine("文件没有子元素可以删除");
public override void Render(int depth)
{
Console.WriteLine(new string('-', depth) + Name);
}
}
// 组合节点:文件夹
public class Folder : FileSystemElement
{
private List<FileSystemElement> children = new List<FileSystemElement>();
public Folder(string name) : base(name) { }
public override void AddChild(FileSystemElement child) => children.Add(child);
public override void RemoveChild(FileSystemElement child) => children.Remove(child);
public override void Render(int depth)
{
Console.WriteLine(new string('-', depth) + Name + "/");
foreach (var child in children)
child.Render(depth + 2);
}
}
// 客户端:文件系统
public class FileSystem
{
public FileSystemElement Root = new Folder("根目录");
public void Render()
{
Root.Render(0);
}
}
class Program
{
static void Main(string[] args)
{
var fileSystem = new FileSystem();
var systemFolder = new Folder("系统文件夹");
systemFolder.AddChild(new File("Windows.exe"));
systemFolder.AddChild(new File("cmd.exe"));
var dataFolder = new Folder("数据文件夹");
dataFolder.AddChild(new File("data.txt"));
dataFolder.AddChild(new File("user.db"));
var userFolder = new Folder("用户文件夹");
userFolder.AddChild(new Folder("文档"));
userFolder.AddChild(new Folder("下载"));
userFolder.AddChild(new Folder("视频"));
userFolder.GetChild<Folder>("文档").AddChild(new File("readme.txt"));
userFolder.GetChild<Folder>("文档").AddChild(new File("book.pdf"));
fileSystem.Root.AddChild(systemFolder);
fileSystem.Root.AddChild(dataFolder);
fileSystem.Root.AddChild(userFolder);
fileSystem.Render();
}
}
public static class FileSystemElementExtensions
{
public static T GetChild<T>(this Folder folder, string name) where T : FileSystemElement
{
foreach (var element in folder.children)
if (element.GetType() == typeof(T) && element.Name == name)
return (T)element;
return null;
}
}
}
总结
组合模式是一种非常实用的设计模式,可用于树形结构的场景。通过使用组合模式,可以将单个对象和组合对象统一起来,用户操作时也更加方便。
在使用组合模式时,需要注意抽象组件的设计,它应该定义操作组合对象和叶子对象的通用接口。另外,组合节点应该维护一个子对象的列表,以便对子对象进行管理。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C# 设计模式系列教程-组合模式 - Python技术站