C# 设计模式系列教程-组合模式

下面我将详细讲解“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技术站

(0)
上一篇 2023年5月31日
下一篇 2023年5月31日

相关文章

  • 在C#使用字典存储事件示例及实现自定义事件访问器

    在C#中,我们可以使用字典作为存储事件的数据结构来方便地处理事件的订阅和触发。以下是一些实现自定义事件访问器的步骤: 1. 声明事件 首先,我们需要声明事件。事件是一种操作,它在特定条件下会被触发。在C#中,事件可以理解为委托的实例化。下面是一个声明事件的示例: public event Action<string> MyEvent; 这里声明了…

    C# 2023年5月31日
    00
  • 基于MVC4+EasyUI的Web开发框架之附件上传组件uploadify的使用

    基于MVC4+EasyUI的Web开发框架之附件上传组件uploadify的使用 什么是uploadify uploadify是一款基于jQuery的上传文件组件,使用uploadify可以方便地在网页中实现文件上传和管理功能。uploadify功能强大,支持多文件上传、拖拽上传、进度条显示、文件类型限制等特性。 如何使用uploadify 引入upload…

    C# 2023年5月31日
    00
  • c#使用wmi查询usb设备信息示例

    下面我将为您详细讲解如何使用c#和wmi查询usb设备信息: 1. 什么是WMI? WMI即Windows Management Instrumentation(Windows管理规范),是微软在Windows NT 4.0中推出的一个系统管理标准。它提供了一种机制,用于通过应用程序编程接口(API)收集有关计算机系统硬件、软件甚至网络服务的信息。我们可以通…

    C# 2023年6月3日
    00
  • Prototype Object对象 学习

    Prototype Object对象是JavaScript中的一个非常重要的概念,理解它可以帮助我们更好地理解JavaScript中的面向对象编程及其工作原理。以下是学习Prototype Object对象的完整攻略: 什么是Prototype Object对象 Prototype Object对象是JavaScript中每个对象都具有的属性,它是一个指向另…

    C# 2023年5月31日
    00
  • C#中Stopwatch的使用及说明

    C#中Stopwatch的使用及说明 什么是Stopwatch Stopwatch是C#中用来计算代码块执行时间的类。它通过记录时间戳(以当前系统时钟为基础),来计算代码块执行所需的时间。 导入Stopwatch命名空间 在使用Stopwatch类之前,需要导入System.Diagnostics命名空间,这可以通过在代码开头添加以下语句来实现: using…

    C# 2023年6月1日
    00
  • C#词法分析器之转换DFA详解

    C#词法分析器之转换DFA详解 什么是词法分析? 词法分析(Lexical Analysis)是编译器中的一个步骤,也称为扫描器(Scanner)。词法分析的主要任务是将程序中的代码转换成一个个Token(标记)。Token是指单词或符号等,是编译器中的最小单位。 词法分析器的输入是源代码,识别出其中的每个Token,每个Token包括 Token种类 和 …

    C# 2023年6月7日
    00
  • C#实现简易计算器功能(2)(窗体应用)

    C#实现简易计算器功能(2)(窗体应用) 前言 在上一篇教程C#实现简易计算器功能(1)中,我们使用控制台应用程序的方式实现了简易的计算器功能。但是,控制台程序的界面比较简陋,不够直观、美观。在这篇教程中,我们将使用Windows窗体应用程序的方式来实现简易计算器功能,界面将更加直观、友好。 步骤 1. 新建Windows窗体应用程序工程 打开Visual …

    C# 2023年6月6日
    00
  • C#实现将汉字转化为2位大写的16进制Unicode的方法

    下面是“C#实现将汉字转化为2位大写的16进制Unicode的方法”的详细攻略: 标准的Unicode编码格式 Unicode编码格式表示了计算机中所有可能用到的字符,包括英文字母、数字、标点符号和各种语言的文字。其中,汉字的Unicode编码范围是0x4E00到0x9FFF。 在C#中,可以使用\u关键字来表示Unicode编码,如\u4E00表示汉字“一…

    C# 2023年5月31日
    00
合作推广
合作推广
分享本页
返回顶部