设计模式 --6组合模式

news2024/11/21 0:24:40

文章目录

    • 组合模式应用场景
    • 组合模式概念
    • 组合模式结构图
    • 透明方式和安全方式
    • 什么时候使用组合模式
    • 公司管理系统使用 组合模式来构架
    • 组合模式的好处

组合模式应用场景

整体和部分可以被一致性对待 比如人力资源部 财务部的管理功能可以复用于分公司的功能
可以引入一种 树状的结构 来统一管理

组合模式概念

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

组合模式结构图

在这里插入图片描述


#include <iostream>
#include <list>
using namespace std;

//组合中对象声明接口 实现所有类共有的默认接口行为
class Component {
public:
	Component(string name)
	{
		this->name = name;
	}
	virtual void Add(Component *c) {};
	virtual void Remove(Component* c) {};
	virtual void Display(int depth) {};//展示参数表示数的深度


protected:
	string name;
};


// 在组合里面表示叶子节点对象 叶节点没有子节点
class Leaf :public Component
{
public:
	Leaf(string name) :Component(name) {

	}
	void Add(Component* c) override {
		cout << "cannot add to a leaf " << endl;
	}

	void Remove(Component* c) override {
		cout << "cannot Remove from  a leaf " << endl;
	}

	void Display(int depth) override {
		string a = string(depth, '-');
		cout << a << name << endl;
	}

};

//在组合里面定义有子节点行为 用来存储子部件
class Composite : public Component
{
public:
	Composite(string name) :Component(name) {

	}
	void Add(Component *c) override {
		children.push_back(c);
	}
	void Remove(Component *c) override {
		children.remove(c);
	}

	void Display(int depth)override
	{
		cout << string(depth, '-') << name << endl;

		for (auto Com : children)
		{
			Com->Display(depth + 2);
		}
	}



private:
	list<Component*> children;
};

int main()
{
	Composite * root = new Composite("root");
	root->Add(new Leaf("Leaf A"));
	root->Add(new Leaf("Leaf B"));

	Composite* comp = new Composite("Composite X");
	comp->Add(new Leaf("Leaf XA"));
	comp->Add(new Leaf("Leaf XB"));

	root->Add(comp);

	Composite *comp2 = new Composite("Composite XY");
	comp2->Add(new Leaf("Leaf XYA"));
	comp2->Add(new Leaf("Leaf XYB"));

	comp->Add(comp2);

	root->Add(new Leaf("Leaf C"));
	Leaf * leaf = new Leaf("Leaf D");
	root->Add(leaf);
	root->Remove(leaf);
	root->Display(1);

	return 0;
}

代码运行结果能显示出 树状的组件
在这里插入图片描述

透明方式和安全方式

透明方式
在这种实现里面 Component 中声明了所有用来管理子对象的方法 对于外界来说 叶子节点和子节点没有区别 它们具有完全一样的接口 Leaf 本身不具备Add Remove方法 所以实现它是没有任何意义的
安全方式
在Component里面不去声明Add 和 Remove方法 这样子类Left不需要去实现,而是在Composite声明所有用来管理子类对象的方法 这样做就不会遇到刚才遇到的问题 但是由于不够透明 所以树枝类将不具有相同的接口 客户端的调用需要做判断

应该视情况 来决定使用哪一种方式

什么时候使用组合模式

需求中体现部分和整体层次的结构的时候 希望用户可以忽略组合对象和单个对象的不同,统一地使用组合结构中的所有对象时 ,就应该考虑使用组合模式了
TreeView 控件使用的就是组合模式

公司管理系统使用 组合模式来构架

在这里插入图片描述


#include <iostream>
#include <list>
using namespace std;

//组合中对象声明接口 实现所有类共有的默认接口行为
class Company {
public:
	Company(string name)
	{
		this->name = name;
	}
	virtual void Add(Company *c) = 0;
	virtual void Remove(Company* c) = 0;
	virtual void Display(int depth) =0 ;//展示参数表示数的深度
	virtual void LineOfDuty() =0; //履行职责


protected:
	string name;
};


// 人力资源部门
class HRDepartment :public Company
{
public:
	HRDepartment(string name) :Company(name) {

	}
	void Add(Company* c) override {
		cout << "cannot add to a leaf " << endl;
	}

	void Remove(Company* c) override {
		cout << "cannot Remove from  a leaf " << endl;
	}

	void Display(int depth) override {
		string a = string(depth, '-');
		cout << a << name << endl;
	}
	void LineOfDuty()override
	{
		cout << name<<" 员工招聘培训管理 " << endl;
	}

};

//具体公司类 实现接口 树枝节点
class ConcreteCompany : public Company
{
public:
	ConcreteCompany(string name) :Company(name) {

	}
	void Add(Company *c) override {
		children.push_back(c);
	}
	void Remove(Company *c) override {
		children.remove(c);
	}

	void Display(int depth)override
	{
		cout << string(depth, '-') << name << endl;

		for (auto Com : children)
		{
			Com->Display(depth + 2);
		}
	}
	//履行职责
	void LineOfDuty() override {
		for (auto Com : children)
		{
			Com->LineOfDuty();
		}
	}


private:
	list<Company*> children;
};

//财务部
class FinanceDepartment :public Company
{
public:
	FinanceDepartment(string name) :Company(name) {

	}
	void Add(Company* c) override {
		cout << "cannot add to a leaf " << endl;
	}

	void Remove(Company* c) override {
		cout << "cannot Remove from  a leaf " << endl;
	}

	void Display(int depth) override {
		string a = string(depth, '-');
		cout << a << name << endl;
	}
	void LineOfDuty()override
	{
		cout << name << " 公司财务收支管理 " << endl;
	}

};

int main()
{
	ConcreteCompany * root = new ConcreteCompany("北京总公司");
	root->Add(new HRDepartment("总公司人力资源"));
	root->Add(new HRDepartment("总公司财务部门"));

	ConcreteCompany* comp = new ConcreteCompany("上海华东分公司");
	comp->Add(new HRDepartment("华东分公司人力资源部"));
	comp->Add(new HRDepartment("华东分公司财务部"));

	root->Add(comp);

	ConcreteCompany *comp2 = new ConcreteCompany("南京办事处");
	comp2->Add(new HRDepartment("南京办事处人力资源部"));
	comp2->Add(new HRDepartment("南京办事处财务部"));
	comp->Add(comp2);

	ConcreteCompany* comp1 = new ConcreteCompany("杭州办事处");
	comp1->Add(new HRDepartment("杭州办事处人力资源部"));
	comp1->Add(new HRDepartment("杭州办事处财务部"));

	comp->Add(comp1);

	cout << "结构图 :" << endl;
	root->Display(1);
	cout << "职责:" << endl;
	root->LineOfDuty();

	return 0;
}

运行后的结果图
在这里插入图片描述

组合模式的好处

组合模式定义基本对象和分公司 办事处结合对象的类层次结构 基本对象可以被组合成更复杂的类型
组合对象又可以被组合 这样不断地柜下去 客户代码 任何用到基本对象的地方都可以使用组合对象

组合模式让客户可以一致的使用组合结构和单个对象

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LLM之RAG实战(三十八)| RAG分块策略之语义分块

在RAG应用中&#xff0c;分块是非常重要的一个环节&#xff0c;常见的分块方法有如下几种&#xff1a; Fixed size chunkingRecursive ChunkingDocument Specific ChunkingSemantic Chunking a&#xff09;Fixed size chunking&#xff1a;这是最常见、最直接的分块方法。我们…

final、finally、finalize有什么区别?

引言 在Java编程语言中&#xff0c;final、finally和finalize是三个具有不同用途和语义的关键字或方法。它们在编程和面试中经常被提及&#xff0c;因此理解它们之间的区别是非常重要的。 题目 final、finally、 finalize有什么区别&#xff1f; 典型回答 final&#xff1…

qt5-入门-2D绘图-Graphics View 架构

参考&#xff1a; Qt Graphics View Framework_w3cschool https://www.w3cschool.cn/learnroadqt/4mvj1j53.html C GUI Programming with Qt 4, Second Edition 本地环境&#xff1a; win10专业版&#xff0c;64位&#xff0c;Qt 5.12 基础知识 QPainter比较适合少量绘图的情…

基于ssm+vue+Mysql的房屋租赁系统求租合同

开发语言&#xff1a;Java框架&#xff1a;ssmJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;Maven3.…

Qt+Ubuntu20.04:打包qt

打包程序 参考 qt项目在Linux平台上面发布成可执行程序.run_qt.run不是虚拟机的配置文件-CSDN博客 Linux下Qt程序的打包发布(1)-不使用第三方工具 - 知乎 (zhihu.com) 过程 1、Release编译 先将你的程序在release下编译通过&#xff0c;保证下面打包的程序是你最新的。 2…

基于Matlab使用深度学习的多曝光图像融合

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 在图像处理领域&#xff0c;多曝光图像融合技术是一种重要的技术&#xff0c;它可以将不同曝光条件下…

【记录】Python3| 将 PDF 转换成 HTML/XML(✅⭐pdfminer.six)

本文将会被汇总至 【记录】Python3&#xff5c;2024年 PDF 转 XML 或 HTML 的第三方库的使用方式、测评过程以及对比结果&#xff08;汇总&#xff09;&#xff0c;更多其他工具请访问该文章查看。 注意&#xff01;pdfminer.six 和 pdfminer3k 不是同一个&#xff01;&#xf…

闪存存储和制造技术概述

闪存存储技术 引言 性能由高到低排序&#xff1a;SLC -> MLC -> TLC -> QLC 根据这个排序读写速度也越来越低&#xff0c;价格越来越便宜 1. SLC SLC&#xff08;Single-Level Cell&#xff0c;单层单元&#xff09;&#xff1a; SLC 闪存具有最高的性能、耐用性和可…

linus下Anaconda创建虚拟环境pytorch

一、虚拟环境 1.创建 输入下面命令 conda create -n env_name python3.8 输入y 2.激活环境 输入 conda activate env_name 二、一些常用的命令 在Linux的控制平台 切换到当前的文件夹 cd /根目录/次目录 查看conda目录 conda list 查看pip目录 pip list查看历史命…

三. Django项目之电商购物商城 -- 校验用户名 , 数据入库

Django项目之电商购物商城 – 校验用户名 , 数据入库 需要开发文档和前端资料的可私聊 一. 路由匹配获得用户名 在注册时 , 用户输入用户名 , 通过ajax请求发送到服务器 , 在路由中设置对应url , 响应视图 , 将用户输入的用户名传入视图 , 与数据库进行校验检查用户名是否重…

安全免费的远程软件有哪些?

远程访问软件&#xff0c;又称远程协助软件或远程控制软件&#xff0c;正在迅速走红。这类软件无论您身处何地&#xff0c;都能轻松实现远程访问和计算机控制。对于个人而言&#xff0c;远程控制工具使工作更加灵活、便捷&#xff1b;而对企业而言&#xff0c;远程访问软件也是…

【webrtc】MessageHandler 1: 基于线程的消息处理:以10毫秒处理音频为例

基于m98 G:\CDN\rtcCli\m98\src\audio\null_audio_poller.h分发的消息由MessageHandler 类通过其抽象接口OnMessage 实现处理 NullAudioPoller NullAudioPoller 是一个处理audio的消息的分发器 poll 启动:

spring boot运行过程中动态加载Controller

1.被加载的jar代码 package com.dl;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplication public class App {public static void main(String[] args) {SpringApplication.run(A…

自学Vue3 Day2

一、组合式Api组件通信 1.父与子之间 父传子&#xff1a;父导入子组件&#xff0c;定义好数据&#xff0c;子组件用props接收&#xff0c;这里defineProps底层本质还是props. 注意模板渲染过程不需要写props 子传 父&#xff1a; 2.模版引用&#xff08;ref&#xff09;和组…

学习VUE2第6天

一.请求拦截器 可以节流&#xff0c;防止多次点击请求 toast是单例 二.前置路由守卫 在Vue.js中&#xff0c;前置路由守卫是指在路由转换实际发生之前执行的钩子函数。这是Vue Router&#xff08;Vue.js官方的路由管理器&#xff09;提供的一种功能&#xff0c;允许开发者在用…

Django后台项目开发实战四

用户可以浏览工作列表以及工作详情 第四阶段 在 jobs 文件夹下创建 templates 文件夹&#xff0c;在里面创建 base.html 网页&#xff0c;内容如下 <!-- base.html --> <div style"text-align:center;"><h1 style "margin:auto; width:50%;&…

DS高阶:图论基础知识

一、图的基本概念及相关名词解释 1.1 图的基本概念 图是比线性表和树更为复杂且抽象的结&#xff0c;和以往所学结构不同的是图是一种表示型的结构&#xff0c;也就是说他更关注的是元素与元素之间的关系。下面进入正题。 图是由顶点集合及顶点间的关系组成的一种数据结构&…

基于网络爬虫技术的网络新闻分析参考论文(论文 + 源码)

【免费】基于网络爬虫技术的网络新闻分析系统.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89248815 基于网络爬虫技术的网络新闻分析 摘 要 自从大数据的概念被提出后&#xff0c;互联网数据成为了越来越多的科研单位进行数据挖掘的对象。网络新闻数据占据了…

EasyRecovery2024汉化版电脑数据恢复软件下载

EasyRecovery是一款功能强大的数据恢复软件&#xff0c;其主要功能包括但不限于以下几点&#xff1a; 硬盘数据恢复&#xff1a;能够扫描本地计算机中的所有卷&#xff0c;建立丢失和被删除文件的目录树&#xff0c;实现硬盘格式化、重新分区、误删数据、重建RAID等硬盘数据恢…

RTSP,RTP,RTCP

机器学习 Machine Learning&#xff08;ML&#xff09; 深度学习&#xff08;DL&#xff0c;Deep Learning&#xff09; CV计算机视觉&#xff08;computer vision&#xff09; FFMPEG&#xff0c;MPEG2-TS,H.264,H.265,AAC rstp,rtp,rtmp,webrtc onvif,gb28181 最详细的音…