模式简介
组合模式是一种结构型设计模式,用于将节点及节点容器看作统一的节点对象,使得调用者无需关注是单个节点还是一组节点,只需要通过接口方法直接调用即可。最直观的和最常见的例子就是文件系统,文件系统中的文件夹和文件都看作是文件系统节点,文件夹下面可以包括文件和文件夹,这种树形层次的文件结构就是对组合模式的一种应用。
常见的应用场景:文件系统、菜单系统、GUI界面布局等。
模式结构
-
Component(组件):声明了组合中对象的接口,可以是一个抽象类或接口,其中定义了一些用于管理子对象的方法,如添加、删除、获取子对象等。
-
Leaf(叶子):是组合中的叶子节点对象,它没有子对象。实现了组件接口,但是在叶子节点中,这些方法可能是空的实现或抛出异常。
-
Composite(容器):是包含子对象的容器节点对象,它通常会实现组件接口的方法,并包含一个集合用于存储子对象。
-
Client(客户端):通过组件接口与组合中的对象进行交互,不需要知道是处理叶子节点还是容器节点,从而可以统一处理整体和部分。
工作原理
-
统一接口:组合模式的核心思想是将叶子节点和容器节点都视为组件,它们都实现了相同的接口,这样客户端可以一致地对待单个对象和对象的组合。
-
递归组合:容器节点内部包含了子对象,这些子对象可以是叶子节点,也可以是容器节点,从而形成了一个递归的结构。
-
透明性:在透明组合模式中,客户端不需要判断当前处理的是叶子还是容器,直接通过组件接口进行操作。在安全组合模式中,客户端需要进行类型检查来确定如何操作。
-
简化客户端代码:通过组合模式,客户端代码不再需要关心处理的是单个对象还是对象的组合,简化了客户端代码,提高了系统的灵活性和可维护性。
代码示例(C#)
提示:可在本栏目的资源篇“设计模式代码示例合集”下载所有完整代码资源。
文件系统节点:FileSystemNode.cs
namespace CompositePattern;
// 文件系统节点
abstract class FileSystemNode
{
protected string name; // 名称
public FileSystemNode(string name)
{
this.name = name;
}
// 显示,level代表文件系统节点所在层级,根节点为1,根节点的一级子节点则为2,依次类推
public abstract void Show(int level);
}
// 文件
class File : FileSystemNode
{
public File(string name) : base(name) { }
public override void Show(int level)
{
Console.WriteLine(new string('-', level) + name);
}
}
// 文件夹
class Directory : FileSystemNode
{
private List<FileSystemNode> fileSystemNodes; // 文件系统节点集合
public Directory(string name) : base(name)
{
fileSystemNodes = new List<FileSystemNode>();
}
// 添加文件系统节点
public void Add(FileSystemNode fileSystemNode)
{
fileSystemNodes.Add(fileSystemNode);
}
// 移除文件系统节点
public void Remove(FileSystemNode fileSystemNode)
{
fileSystemNodes.Remove(fileSystemNode);
}
public override void Show(int level)
{
Console.WriteLine(new string('-', level) + name);
for (int i = 0; i < fileSystemNodes.Count; i++)
{
fileSystemNodes[i].Show(level + 1);
}
}
}
测试代码:Program.cs
// ************* 11.组合模式测试 **************
// 创建三个文件和两个文件夹
CompositePattern.File fileA = new CompositePattern.File("文件A");
CompositePattern.File fileB = new CompositePattern.File("文件B");
CompositePattern.File fileC = new CompositePattern.File("文件C");
CompositePattern.Directory directoryA = new CompositePattern.Directory("文件夹A");
CompositePattern.Directory directoryB = new CompositePattern.Directory("文件夹B");
// 文件夹B中包含文件A和文件C
directoryB.Add(fileA);
directoryB.Add(fileC);
// 文件夹A中包含文件B和文件夹B
directoryA.Add(fileB);
directoryA.Add(directoryB);
// 显示文件夹A及其目录下的所有子文件夹和子文件
directoryA.Show(1);
代码解说
上述代码简单模拟了文件系统中文件夹和文件的层次结构。文件夹和文件都继承自文件系统节点类,文件夹作为文件系统节点的容器。文件夹A下包含文件B和文件夹B,文件夹B下包含文件A和文件C。通过组合模式简化了调用逻辑,并提升了该文件系统的可扩展性,降低了维护成本,例如未来需要加入一种加密型文件夹,那么就可以直接让其继承文件系统节点类,而不需要去修改文件系统的源代码。
如果这篇文章对你有帮助,请给作者点个赞吧!