设计模式之 组合模式
组合模式(Composite Pattern)是一种结构型设计模式,它通过将对象组合成树形结构来表示“部分-整体”层次。组合模式允许客户端统一处理单个对象和对象集合。换句话说,组合模式让客户端可以像处理单个对象一样处理对象的集合,使得树形结构的操作更加简单,提升了系统的灵活性。
在组合模式中,既可以将单个对象(叶子节点)与容器对象(树枝节点)进行统一处理,树枝节点本身也可以拥有其他树枝节点或叶子节点,从而形成一个递归的结构。组合模式通过递归的方式使得对整体对象的操作能够像对单个对象的操作一样。
一、组合模式的结构
组合模式通常由以下几个角色组成:
-
组件(Component):
组件角色通常是一个抽象类或者接口,定义了组合对象和叶子节点都需要实现的通用接口。它可以声明一个操作,并提供默认实现(如果需要的话)。 -
叶子节点(Leaf):
叶子节点是组合中的基本元素,它没有子对象。叶子节点类通常会实现组件接口,并定义自己的业务逻辑。 -
树枝节点(Composite):
树枝节点(也叫容器节点)是组合中的复杂对象,它可以包含叶子节点或其他树枝节点。树枝节点同样会实现组件接口,并通常会在其内部维护子节点的集合(子树)。树枝节点负责对其子节点的管理,并能够通过组件接口向外部暴露操作。 -
客户端(Client):
客户端通过组件接口操作组合中的对象,无论是单个叶子节点还是包含多个节点的树枝节点。客户端不需要关心这些对象是如何组织和管理的,可以通过统一的接口来执行操作。
二、组合模式的工作原理
组合模式的工作原理基于递归结构:组件(Component)接口统一了所有节点的行为,树枝节点(Composite)负责管理其子节点,并能够执行与其相关的操作,叶子节点(Leaf)则是最基本的元素,它没有子节点,也执行具体的操作。客户端通过组件接口与树枝节点或叶子节点进行交互,而不需要关心具体的结构。
在实际操作时,客户端可以像对待单个对象一样,使用统一的接口来调用操作。而树枝节点则负责将操作转发给其子节点,并根据子节点的不同进行处理。这样,组合模式隐藏了复杂的层次结构,提供了统一而简单的接口。
三、组合模式的示例
假设我们在设计一个文件管理系统,该系统包含文件(叶子节点)和文件夹(树枝节点)。文件夹中可以包含多个文件或文件夹。客户端需要能够像操作文件一样操作文件夹和文件。
-
组件抽象类
public abstract class MenuComponent {protected String name;protected int level;public void add(MenuComponent menuComponent){throw new UnsupportedOperationException();}public void remove(MenuComponent menuComponent){throw new UnsupportedOperationException();}public MenuComponent getChild(int index){throw new UnsupportedOperationException();}public String getName(){return name;}public abstract void print(); }
-
叶子节点类
public class MenuItem extends MenuComponent{public MenuItem(String name, int level) {this.name = name;this.level = level;}@Overridepublic void print() {for (int i = 0; i < level;i++){System.out.print("--");}System.out.println(name);} }
-
树枝节点类
public class Menu extends MenuComponent{private List<MenuComponent> list = new ArrayList<>();public Menu(String name,int level){this.name = name;this.level = level;}@Overridepublic void add(MenuComponent menuComponent) {list.add(menuComponent);}@Overridepublic void remove(MenuComponent menuComponent) {list.remove(menuComponent);}@Overridepublic MenuComponent getChild(int index) {return list.get(index);}@Overridepublic void print() {for (int i = 0; i < level;i++){System.out.print("--");}System.out.println(name);list.forEach(menuComponent -> {menuComponent.print();});} }
-
客户端代码
public class Client {public static void main(String[] args) {MenuComponent menu1 = new Menu( "菜单管理", 2);menu1.add( new MenuItem("页面访问", 3));menu1.add( new MenuItem("展开菜单", 3));menu1.add( new MenuItem("编辑菜单",3));menu1.add( new MenuItem("删除菜单", 3));menu1.add( new MenuItem( "新增菜单",3));MenuComponent menu2 = new Menu( "权限管理", 2);menu2.add(new MenuItem( "页面访问",3)) ;menu2.add(new MenuItem( "提交保存", 3)) ;MenuComponent menu3 = new Menu( "角色管理",2);menu3.add( new MenuItem("页面访问", 3));menu3.add( new MenuItem( "新增角色", 3));menu3.add( new MenuItem( "修改角色", 3));MenuComponent component = new Menu( "系统管理", 1);component.add(menu1);component.add(menu2);component.add(menu3);component.print();} }
-
运行结果
四、组合模式的优缺点
优点:
-
统一的接口:
客户端通过统一的接口来处理单个对象和对象集合(树形结构),无需关心不同类型的节点。树枝节点和叶子节点都实现了相同的接口,客户端可以以相同的方式进行操作。 -
树形结构:
组合模式非常适用于树形结构的数据管理。树形结构可以灵活地表示部分和整体的关系,例如文件夹和文件、组织结构等。 -
简化客户端代码:
由于客户端只需操作组件接口,它不需要关注具体的对象是叶子节点还是树枝节点,从而简化了客户端的代码。 -
递归的组织方式:
组合模式适合处理递归结构(例如文件系统或图形界面),能够非常方便地处理嵌套的复杂对象。
缺点:
-
可能过于泛化:
由于组合模式把叶子节点和树枝节点统一成一个组件接口,它可能会把一些不需要的操作暴露给客户端。例如,某些操作仅适用于树枝节点,但它们也可能被客户端用来操作叶子节点。 -
性能问题:
如果树的深度较大或树的结构过于复杂,操作的效率可能会下降,尤其是递归调用时,可能会导致性能瓶颈。 -
不容易改变叶子节点的行为:
在某些场景下,叶子节点的行为可能无法满足需求,尤其是在不考虑继承和多态的情况下。扩展叶子节点的行为可能会相对复杂。
五、组合模式的应用场景
-
树形结构的数据表示:
组合模式非常适合表示树形结构的对象,如文件系统中的文件夹和文件、组织架构、公司中的部门和员工等。 -
图形和界面组件:
在图形界面系统中,界面组件常常是嵌套的。一个复杂的UI组件可以包含多个子组件(如按钮、文本框、图片等),这些子组件又可能包含其他的子组件。组合模式能够将这些组件管理成一个树形结构,简化界面组件的管理和渲染。 -
多层嵌套的对象集合:
组合模式适用于需要将多个对象嵌套在一起并统一管理的场景,尤其是在需要进行递归操作的场合,如组织结构图、公司账目管理等。 -
需要部分和整体一致性操作的场景:
如果客户端需要对部分和整体都进行相同的操作,组合模式是一个理想选择。无论是单独的叶子节点,还是包含多个子节点的树枝节点,都可以通过统一的接口来进行操作。
相关文章:
设计模式之 组合模式
组合模式(Composite Pattern)是一种结构型设计模式,它通过将对象组合成树形结构来表示“部分-整体”层次。组合模式允许客户端统一处理单个对象和对象集合。换句话说,组合模式让客户端可以像处理单个对象一样处理对象的集合&#…...
LCR 001 两数相除
一.题目: . - 力扣(LeetCode) 二.原始解法-超时: class Solution: def divide(self, a: int, b: int) -> int: # 1)分析: # 除法计算,不能使用除法符号,可以理解为实现除法 # 除法…...
数据库、数据仓库、数据湖、数据中台、湖仓一体的概念和区别
数据库、数据仓库、数据湖、数据中台和湖仓一体是数据管理和分析领域的不同概念,各自有不同的特点和应用场景。以下是它们的主要区别: 1. 数据库(Database) 定义:结构化的数据存储系统,用于高效地存储、检…...
vue 的生命周期函数
Vue 生命周期函数(生命周期钩子)是 Vue 实例从创建到销毁过程中,不同阶段所触发的特定函数。理解这些生命周期函数对于开发 Vue 应用至关重要,因为它们让你在不同的生命周期阶段执行代码,比如数据初始化、DOM 渲染完成…...
单片机UART协议相关知识
概念 UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器) 是一种 异步 串行 全双工 通信协议,用于设备一对一进行数据传输,只需要两根线(TX,RX)。 异步&…...
【操作系统不挂科】<CPU调度(13)>选择题(带答案与解析)
前言 大家好吖,欢迎来到 YY 滴 操作系统不挂科 系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 本博客主要内容,收纳了一部门基本的操作系统题目,供yy应对期中考试复习。大家可以参考 本章为选择题题库,试…...
OpenCV笔记:图像去噪对比
图像去噪对比 1. 均值滤波(Mean Filtering) 方法:用像素周围的像素平均值替换每个像素值。适用场景:适用于去除随机噪声,如在不强调图像细节的场景中,如果图像细节较多时,可能会导致图像模糊。…...
A-B数对(二分查找)
#include<bits/stdc.h> using namespace std;using ll long long;int main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);int n,c;cin>>n>>c;int nu[200000];for(int i0;i<n;i){cin>>nu[i]; // 输入数组元素}sort(nu,nun);ll cnt0; // 统计满…...
Vue 的各个生命周期
详解 Vue 的各个生命周期 文章目录 详解 Vue 的各个生命周期Vue 组件的生命周期1.1 创建阶段示例: 1.2 挂载阶段示例: 1.3 更新阶段示例: 1.4 销毁阶段示例: 生命周期总结生命周期钩子对比表参考链接 Vue 组件的生命周期 在 Vue …...
实现简易计算器 网格布局 QT环境 纯代码C++实现
问题:通过代码完成一个10以内加减法计算器。不需要自适应,界面固定360*350。 ""按钮90*140,其它按钮90*70。 参考样式 #define DEFULT_BUTTON_STYLE "\ QPushButton{\color:#000000;\border:1px solid #AAAAAA;\border-radi…...
后端开发详细学习框架与路线
🚀 作者 :“码上有前” 🚀 文章简介 :后端开发 🚀 欢迎小伙伴们 点赞👍、收藏⭐、留言💬 为帮助你合理安排时间,以下是结合上述学习内容的阶段划分与时间分配建议。时间安排灵活&a…...
2.langchain中的prompt模板 (FewShotPromptTemplate)
本教程将介绍如何使用 LangChain 库中的 PromptTemplate 和 FewShotPromptTemplate 来构建和运行提示(prompt),并通过示例数据展示其应用。 安装依赖 首先,确保你已经安装了 langchain 和相关依赖: pip install lan…...
FairGuard游戏加固实机演示
此前,FairGuard对市面上部分游戏遭遇破解的案例进行了详细分析,破解者会采用静态分析与动态调试相结合的手段,逆向分析出代码逻辑并对其进行篡改,实现作弊功能,甚至是对游戏资源文件进行篡改,从而制售外挂。…...
Spark使用过程中的 15 个常见问题、详细解决方案
目录 问题 1:Spark 作业超时问题描述解决方案Python 实现 问题 2:内存溢出问题描述解决方案Python 实现 问题 3:Shuffle 性能问题问题描述解决方案Python 实现 问题 4:Spark 作业调度不均问题描述解决方案Python 实现 问题 5&…...
算法【最长递增子序列问题与扩展】
本文讲解最长递增子序列以及最长不下降子序列的最优解,以及一些扩展题目。本文中讲述的是最优解,时间复杂度是O(n*logn),空间复杂度O(n),好实现、理解难度不大。这个问题也可以用线段树来求解,时间和空间复杂度和本节讲…...
k8s篇之flannel网络模型详解
在 Kubernetes (K8s) 中,Flannel 是一种常用的网络插件,用于实现容器之间的网络通信。Flannel 提供了一种覆盖网络(Overlay Network)模型,使得容器可以跨多个主机进行通信。 以下是 Flannel 在 Kubernetes 中的详细工作原理和覆盖网络模型的详解: 1.Flannel 简介 Flann…...
windows 和 linux检查操作系统基本信息
windows检查操作系统基本信息 systeminfolinux检查操作系统基本信息 获取系统位数 getconf LONG_BIT查询操作系统release信息 lsb_release -a查询系统信息 cat /etc/issue查询系统名称 uname -a...
Oracle OCP认证考试考点详解082系列22
题记: 本系列主要讲解Oracle OCP认证考试考点(题目),适用于19C/21C,跟着学OCP考试必过。 105. 第105题: 题目 解析及答案: 题目翻译: 关于Oracle数据库中的事务请选择两个正确的陈述…...
线性回归 - 最小二乘法
线性回归 一 简单的线性回归应用 webrtc中的音视频同步。Sender Report数据包 NTP Timestamp(网络时间协议时间戳):这是一个64位的时间戳,记录着发送SR的NTP时间戳,用于同步不同源之间的时间。RTP Timestamp࿱…...
Linux - 线程基础
文章目录 1.什么是线程2.线程vs进程3.线程调度4.线程控制4.1 POSIX线程库4.2创建线程4.3线程终止4.4线程等待4.5线程分离 5、线程封装 1.什么是线程 在Linux操作系统中,线程是进程内部的一个执行流。在Linux操作系统下,执行流统称为轻量级进程࿰…...
网络爬虫——分布式爬虫架构
分布式爬虫在现代大数据采集中是不可或缺的一部分。随着互联网信息量的爆炸性增长,单机爬虫在性能、效率和稳定性上都面临巨大的挑战。分布式爬虫通过任务分发、多节点协作以及结果整合,成为解决大规模数据抓取任务的核心手段。 本节将从 Scrapy 框架的…...
RT_Thread内核源码分析(三)——线程
目录 1. 线程结构 2. 线程创建 2.1 静态线程创建 2.2 动态线程创建 2.3 源码分析 2.4 线程内存结构 3. 线程状态 3.1 线程状态分类 3.2 就绪状态和运行态 3.3 阻塞/挂起状态 3.3.1 阻塞工况 3.4 关闭状态 3.4.1 线程关闭接口 3.4.2 静态线程关闭 3.4.3 动态线程关…...
正排索引和倒排索引
一、简介 正排索引:一个未经处理的数据库中,一般是以文档ID作为索引,以文档内容作为记录。 倒排索引:Inverted index,指的是将单词或记录作为索引,将文档ID作为记录,这样便可以方便地通过单词或…...
丹摩 | 重返丹摩(上)
目录 一.登录平台 二. 数据管理与预处理 1.数据清洗 2.数据格式转换 3.特征工程 二.数据可视化 1.快速可视化 2.数据洞察 3.自定义视图 三.技术支持与帮助 1.技术支持 (1). 帮助文档 (2). 用户社区 2.客服支持 (1). 在线客服 (2). 反馈与建议 总结 一.登录平台…...
Frontend - 防止多次请求,避免重复请求
目录 一、避免重复执行的多种情况 (一)根据用途 (二)根据用户操作 二、具体实现 (一)“Ajax ”结合disabled (防止多次请求),避免多次点击重复请求 1. 适用场景 2. 解决办法 3. 示例 &…...
RHCE的学习(22)
第四章 流程控制之条件判断 条件判断语句是一种最简单的流程控制语句。该语句使得程序根据不同的条件来执行不同的程序分支。本节将介绍Shell程序设计中的简单的条件判断语句。 if语句语法 单分支结构 # 语法1: if <条件表达式> then指令 fi #语法2&#x…...
【前端知识】简单讲讲什么是微前端
微前端介绍 一、定义二、背景三、核心思想四、基本要素五、核心价值六、实现方式七、应用场景八、挑战与解决方案 什么是single-spa一、核心特点二、核心原理三、应用加载流程四、最佳实践五、优缺点六、应用场景 什么是 qiankun一、概述二、特点与优势三、核心功能四、使用场景…...
AWS IAM
一、介绍 1、简介 AWS Identity and Access Management (IAM) 是 Amazon Web Services 提供的一项服务,用于管理 AWS 资源的访问权限。通过 IAM,可以安全地控制用户、组和角色对 AWS 服务和资源的访问权限。IAM 是 AWS 安全模型的核心组成部分,确保只有经过授权的用户和应…...
丹摩|丹摩助力selenium实现大麦网抢票
丹摩|丹摩助力selenium实现大麦网抢票 声明:非广告,为用户体验 1.引言 在人工智能飞速发展的今天,丹摩智算平台(DAMODEL)以其卓越的AI算力服务脱颖而出,为开发者提供了一个简化AI开发流程的强…...
基于Qt/C++/Opencv实现的一个视频中二维码解析软件
本文详细讲解了如何利用 Qt 和 OpenCV 实现一个可从视频和图片中检测二维码的软件。代码实现了视频解码、多线程处理和界面更新等功能,是一个典型的跨线程图像处理项目。以下分模块对代码进行解析。 一、项目的整体结构 项目分为以下几部分: 主窗口 (M…...
如何设置wordpress的语言/google推广方式和手段有哪些
有可能是作用域的问题...
百度做网站要多久/怎么做好推广和营销
采用UITableView显示从网络上下载的图片,因为网络图片下载比较耗费时间,一般采用边显示文字,内容,后台下载图片,下载完成后刷新TableViewCell ,本文将演示如何通过自定的UITableViewCell,显示图…...
网站内做动图/seo体系百科
手机已进入智能化的5G时代,手机的通信技术,硬件技术,软件技术等获得突飞猛进的发展。尤其在近年手机一直在屏幕,摄像头等方面的专注发展,原本最重要的通话功能,短消息功能越来越式微,可取代这两…...
网站建设优化排名/渠道推广平台
Web 开发中几乎的平台都需要一个后台管理,但是从零开发一套后台控制面板并不容易,幸运的是有很多开源免费的后台控制面板可以给开发者使用,那么有哪些优秀的开源免费的控制面板呢?我在 Github 上收集了一些优秀的后台控制面板&…...
网站建设 开发/域名污染查询网站
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼89C51系列单片机都不带SPI口,所在在这种情况下,我们可以模拟SPI口来现实我们要的功能,程序如下://-----------------------函数声明,变量定义--&am…...
宁波网站开发服务/廊坊首页霸屏排名优化
接下来,我们继续我们的FSM有限状态机的设计,在设计三中我们实现了FSState这个类,我们继续实现FSEvent事件处理类。在FSEvent类里面我们声明了FiniteStateMachine里面定义的委托函数。代码如下:protected FiniteStateMachine.Enter…...