设计模式(3)--对象结构(3)--组合

1. 意图

    将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。

2. 三种角色

    抽象组件(Component)、组合式节点(Composite)、叶节点(Leaf)

3. 优点

   3.1 定义了包含基本对象和组合对象的类层次结构。

         客户代码中,用到基本对象的地方都可以使用组合对象。

   3.2 简化客户代码,不需要关心是叶节点还是组合。

   3.3 使得更容易增加新类型的组件

   3.4 使设计变得更加一般化

4. 缺点

    4.1 只能在运行时刻进行类型检查

5. 相关模式

    5.1 通常“部件-父部件”连接用于Responsibility of Chain模式

    5.2 装饰模式经常与Composite模式一起使用,通常有个公共的父类。

    5.3 Flyweight让你共享组件,但不能引用它们的父部件。

    5.4 Iterator可用来遍历Composite

    5.5 Visitor将本来应该分布在Composite和Leaf类中的操作和行为局部化。

6. 代码示意(C++)
#pragma once
#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Component
{
protected:
	string m_strName;
public:	
	Component(const string &strName)
	{
		m_strName = strName;
	}
	virtual void Operation(int depth) = 0;
	
	virtual bool Add(Component* pComponent) = 0;
	virtual bool Remove(Component* pComponent) = 0;
	virtual Component* GetChild(int pos) = 0;
public:
	string GetName() { return m_strName; }
protected:
	string GetPreLine(int depth)
	{
		string preLine = "";
		for (int i = 0; i < depth; ++i)
		{
			preLine += "--";
		}
		return preLine;
	}
};

class Leaf : public Component
{
public:
	Leaf(const string& strName) :Component(strName)
	{
	}
	virtual bool Add(Component* pComponent) {
		cout << "Leaf can't add" << endl;
		return false;
	}
	virtual bool Remove(Component* pComponent) {
		cout << "Leaf can't remove" << endl;
		return false;
	}
	virtual Component* GetChild(int pos) {
		cout << "Leaf has no child" << endl;
		return 0;
	}
	virtual void Operation(int depth) {
		cout << GetPreLine(depth) << m_strName << endl;
	}
};

class Composite :public Component
{
private:
	vector<Component*> m_vecChildren;
public:
	Composite(const string& strName) :Component(strName) {
		m_strName = strName;
	}
	~Composite()
	{
		auto it = m_vecChildren.begin();
		while (it != m_vecChildren.end()) {
			delete* it;
			it++;
		}
		m_vecChildren.clear();
	}
	virtual bool Add(Component* pComponent) {
		if (pComponent == 0) {
			return false;
		}
		m_vecChildren.emplace_back(pComponent);
		//cout << "children size:" <<m_vecChildren.size()<< endl;
		return true;
	}
	virtual bool Remove(Component* pComponent) {
		if (pComponent == 0) {
			return false;
		}
		m_vecChildren.erase(std::remove_if(m_vecChildren.begin(), m_vecChildren.end(), [&](Component *p) { return p->GetName().compare(pComponent->GetName()) == 0; }), m_vecChildren.end());
		//cout << "children size:" << m_vecChildren.size() << endl;
		//cout << "children capacity:" << m_vecChildren.capacity() << endl;
		return true;
	}
	virtual Component* GetChild(int pos) {
		if (pos >= 0 && pos < m_vecChildren.size()) {
			return m_vecChildren[pos];
		}
		return 0;
	}

	virtual void Operation(int depth) {
		cout << GetPreLine(depth) << m_strName << endl;

		auto it = m_vecChildren.begin();
		while (it != m_vecChildren.end()) {
			(*it)->Operation(depth+1);
			it++;
		}
	}
};
#include "Component.h"
int main() {
	Composite* pRoot= new Composite("Root");
	pRoot->Add(new Leaf("Leaf1"));
	pRoot->Add(new Leaf("Leaf2"));

	Composite* pComposite = new Composite("Composite");
	pComposite->Add(new Leaf("Leaf3"));
	
	pRoot->Add(pComposite);
	pRoot->Operation(0);
	cout << "------------------" << endl;

	pRoot->Remove(pComposite);
	pRoot->Operation(0);

	delete pComposite;
	delete pRoot;
}

运行结果:

6.1 组合Composite是一种基本对象Component(3.1)。

6.2 Leaf也是一种基本对象,只需要关注Component接口(3.2)。

6.2 继承Component接口,就可以增加新类型的组件(3.3)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/252456.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

openwrt中taiscale自动安装脚本详解

openwrt中taiscale自动安装脚本详解 一、代码仓库地址 https://github.com/adyanth/openwrt-tailscale-enabler 二、代码仓库中脚本文件详解 主要包含三个脚本分别是etc/init.d/tailscale、usr/bin/tailscale、usr/bin/tailscaled &#xff0c;接下来逐个分析一下脚本中的具…

【Redis】AOF 基础

因为 Redis AOF 的实现有些绕, 就分成 2 篇进行分析, 本篇主要是介绍一下 AOF 的一些特性和依赖的其他函数的逻辑,为下一篇 (Redis AOF 源码) 源码分析做一些铺垫。 AOF 全称: Append Only File, 是 Redis 提供了一种数据保存模式, Redis 默认不开启。 AOF 采用日志的形式来记…

Go标准包之flag命令行参数解析

1.介绍 在 Go中&#xff0c;如果要接收命令行参数&#xff0c;需要使用 flag 包进行解析。不同的参数类型可以通过不同的方法接收。 2.参数接受 2.1 接受方式 使用flag接收参数&#xff0c;可以由以下三种方式接受&#xff1a; 方式一: flag.Type(name,defaultVal,desc)方…

Linux上使用HTTP协议进行数据获取的实战示例

嗨&#xff0c;Linux爱好者们&#xff0c;今天我们要一起探讨一下如何在Linux上进行HTTP协议的数据获取。这不是一项简单的任务&#xff0c;但放心&#xff0c;我会以最简单的语言&#xff0c;结合实例来给大家讲解。 首先&#xff0c;我们需要一个工具&#xff0c;那就是curl…

Python生成器(Generator)(继续更新...)

学习网页&#xff1a; Welcome to Python.orghttps://www.python.org/https://www.python.org/ Python生成器 生成器&#xff08;Generator&#xff09;是 Python 的一种特殊类型的迭代器。生成器允许你创建自己的数据流&#xff0c;每次从数据流中获取一个元素&#xff0c;…

医保电子凭证在项目中的集成应用

随着医保电子凭证使用普及&#xff0c;医疗行业的各个场景都要求支持医保码一码通办&#xff0c;在此分享一下&#xff0c;在C#和js中集成医保电子凭证的demo 供有需要的小伙伴参考。 一、项目效果图 在c#中集成医保电子凭证效果 在js中集成医保电子凭证效果 二、主要代码 c#…

Linux_Docker图形化工具Portainer如何安装并结合内网穿透实现远程访问

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 本文主要介绍如何本地安装Portainer并结合内网穿透工具实现任意浏览器远程访问管理界面。Portainer 是一个轻量级…

算法竞赛备赛进阶之树形DP训练

目录 1.树的最长路径 2.树的中心 3.数字转换 4.二叉苹果树 5.战略游戏 6.皇宫守卫 树形DP是一种动态规划方法&#xff0c;主要用于解决树形结构的问题。在树形DP中&#xff0c;通常会使用动态规划的思想来求解最优化问题。其核心在于通过不断地分解问题和优化子问题来解决…

【理论篇】SaTokenException: 非Web上下文无法获取Request问题解决 -理论篇

在我们使用sa-token安全框架的时候&#xff0c;有时候会提示&#xff1a;SaTokenException:非Web上下文无法获取Request 错误截图&#xff1a; 在官方网站中&#xff0c;查看常见问题排查&#xff1a; 错误追踪&#xff1a; 跟着源码可以看到如下代码&#xff1a; 从源码中&a…

01 整体代码运行流程

文章目录 01 整体代码运行流程1.1 运行官方 Demo1.2 变量命名规则1.3 多线程1.4 线程锁1.5 SLAM 主类 System 01 整体代码运行流程 1.1 运行官方 Demo 以 stereo_kitti 为例&#xff0c;执行 ./stereo_kitti path_to_vocabulary path_to_settings path_to_sequence./stereo_…

大创项目推荐 深度学习 python opencv 实现人脸年龄性别识别

文章目录 0 前言1 项目课题介绍2 关键技术2.1 卷积神经网络2.2 卷积层2.3 池化层2.4 激活函数&#xff1a;2.5 全连接层 3 使用tensorflow中keras模块实现卷积神经网络4 Keras介绍4.1 Keras深度学习模型4.2 Keras中重要的预定义对象4.3 Keras的网络层构造 5 数据集处理训练5.1 …

W25Q64(模拟SPI)读写数据的简单应用

文章目录 一、W25Q64是什么&#xff1f;二、使用步骤1.硬件1.引脚说明2.硬件连接3.设备ID4.内部框架5.指令集指令集1指令集2 2.软件1.W25Q64引脚定义代码如下&#xff08;示例&#xff09;&#xff1a;2.W25Q64初始化代码如下&#xff08;示例&#xff09;&#xff1a;3.W25Q64…

在排序数组中查找元素的第一个和最后一个位置(Java详解)

一、题目描述 给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&#xff0c;返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。 示…

Android开发——组合函数、注解与连接Android设备

1、JetPack Compose、组合函数与注解和文本修改 1、JetPack Compose&#xff1a;Jetpack Compose 是由 Google 推出的用于构建 Android 用户界面的现代化工具包。它是一个声明式的 UI 工具包&#xff0c;用于简化 Android 应用程序的用户界面设计和开发。Jetpack Compose 采用…

02.Git常用基本操作

一、基本配置 &#xff08;1&#xff09;打开Git Bash &#xff08;2&#xff09;配置姓名和邮箱 git config --global user.name "Your Name" git config --global user.email "Your email" 因为Git是分布式版本控制工具&#xff0c;所以每个用户都需要…

02-分组查询group by和having的使用

分组查询 MySQL中默认是对整张表的数据进行操作即整张表为一组, 如果想对每一组的数据进行操作,这个时候我们需要使用分组查询 分组函数的执行顺序: 先根据where条件筛选数据,然后对查询到的数据进行分组,最后也可以采用having关键字过滤取得正确的数据 group by子句 在一条…

【STM32】STM32学习笔记-EXTI外部中断(11)

00. 目录 文章目录 00. 目录01. 中断系统02. 中断执行流程03. STM32中断04. NVIC基本结构05. NVIC优先级分组06. EXTI简介07. EXTI基本结构08. AFIO复用IO口09. EXTI框图10. 计数器模块11. 旋转编码器简介12. 附录 01. 中断系统 中断&#xff1a;在主程序运行过程中&#xff0…

easy贪吃蛇

之前承诺给出一个贪吃蛇项目。 1.EasyX库认知 有关EasyX库的相关信息&#xff0c;您可以看一下官方的文档&#xff1a;EasyX官方文档。 这里我做几点总结&#xff1a; EasyX库就和名字一样&#xff0c;可以让用户调用一些简单的函数来绘制图像和几何图形利用EasyX库可以制作…

ES6 面试题 | 15.精选 ES6 面试题

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

知识付费平台选择指南:如何找到最适合你的学习平台?

在当今的知识付费市场中&#xff0c;用户面临的选择越来越多&#xff0c;如何从众多知识付费平台中正确选择属于自己的平台呢&#xff1f;下面&#xff0c;我们将为您介绍我有才知识付费平台相比同行的优势&#xff0c;帮助您做出明智的选择。 一、创新的技术架构&#xff0c;…