(十)Head first design patterns组合模式(c++)

组合模式

组合模式在参考链接中已经讲得很好了,这里只简单讲讲就好。

组合模式的意图是表达部分-整体层次结构。

当你需要管理一个组合对象,又要管理这个组合对象的单个对象。这个时候就可以让这个组合对象和单个对象继承同一个基类,以便用基类指针做统一管理。

当基类指针去调用operation方法时,如果这个这个指针指向的是Composite对象,则调用的是Composite对象的operation方法,这个方法中的for循环会挨个遍历各个vector中的指针,如果遍历的指针指向的还是Composite对象,则继续调用Composite对象的operation方法。如果指针指向的单元是Leaf对象,则会调用Leaf对象中的operation方法。

如果不是写成组合模式,一般常用的递归函数会怎么写?首先也是遍历父节点,如果父节点有子节点就去遍历子节点,直到遍历完叶子节点。组合模式比较巧妙的是,在编译的时候,虚函数operation已经根据指针是指向基类还是子类分好了,所以递归函数中省去了判断是否是叶子节点的过程,而是让指针自行去判断。(设计模式经常干的一件事就是:把需用判断的地方巧妙的用继承虚函数来实现)

组合模式+迭代器模式

怎么用迭代器的方式去迭代Composite对象呢?

可以相应写一个CompositeIterator对象。迭代器其实有点像一个托管,对象将自己的链接地址给到迭代器,由迭代器的hasNext判断后面还有没数据,由next返回下一个容器对象。

关键代码

next(): 返回下一个对象,同时把composite对象创建的迭代器加入到iterators容器中。

hasNext(): 判断是否可迭代,如果不可迭代则继续删除此迭代器,继续寻找到下一个可迭代的迭代器。找到则返回true。

template<class T>
class CompositeIterator : public Iterator<T>{
public:CompositeIterator(Iterator<T>* iterator){ iterators.push_back(iterator); }T next(){Iterator<T>* iterator = iterators[0];T item = iterator->next();iterator = item->createIterator();if(iterator->hasNext()){ // 这里leaf的迭代器hasNext返回的是false,故而不会添加进去iterators.push_back(iterator);} return item;}bool hasNext(){if(iterators.size()==0) return false;Iterator<T>* iterator = iterators[0];if(!iterator->hasNext()){ iterators.erase(iterators.begin()); // 已经没法迭代了,继续下一个迭代对象return hasNext();} else {return true;}}
private:vector<Iterator<T>*> iterators;
};

统一vsctor接口代码

这里为了让vector的迭代器也有hasNext()和next()接口,重写了一个newVector对象,其行为类似vector。

template<class T>
class Iterator{
public:virtual bool hasNext(){}virtual T next(){}virtual bool isComposite(){}
};
template<class T>
class newVectorIterator : public Iterator<T>{
public:newVectorIterator(vector<T> *p):p(p){}T next(){T t = p->at(position);position++;return t;}bool hasNext(){if(position >= p->size()) return false;elsereturn true;}vector<T> *p;int position = 0;
};
template<class T>
class newVector{
public:void push_back(T item){mVector.push_back(item);}T operator[](int index){return mVector[index];}int size(){return mVector.size();}Iterator<T>* createIterator(){return new newVectorIterator<T>(&mVector);}vector<T> mVector;
};

全部代码

#include<iostream>
#include<string>
#include<vector>
using namespace std;template<class T>
class Iterator{
public:virtual bool hasNext(){}virtual T next(){}virtual bool isComposite(){}
};
template<class T>
class newVectorIterator : public Iterator<T>{
public:newVectorIterator(vector<T> *p):p(p){}T next(){T t = p->at(position);position++;return t;}bool hasNext(){if(position >= p->size()) return false;elsereturn true;}vector<T> *p;int position = 0;
};
template<class T>
class newVector{
public:void push_back(T item){mVector.push_back(item);}T operator[](int index){return mVector[index];}int size(){return mVector.size();}Iterator<T>* createIterator(){return new newVectorIterator<T>(&mVector);}vector<T> mVector;
};template<class T>
class NullIterator : public Iterator<T>{
public:T next(){ return nullptr; }bool hasNext(){ return false; }
};
template<class T>
class CompositeIterator : public Iterator<T>{
public:CompositeIterator(Iterator<T>* iterator){ iterators.push_back(iterator); }T next(){Iterator<T>* iterator = iterators[0];T item = iterator->next();iterator = item->createIterator();if(iterator->hasNext()){iterators.push_back(iterator);} return item;}bool hasNext(){if(iterators.size()==0) return false;Iterator<T>* iterator = iterators[0];if(!iterator->hasNext()){iterators.erase(iterators.begin());return hasNext();} else {return true;}}
private:vector<Iterator<T>*> iterators;
};
class Compoment{
public:virtual ~Compoment(){ std::cout << "~Compoment()" << endl; }virtual void operation() = 0;virtual void operation1() = 0;virtual void add(Compoment *com){}virtual void remove(Compoment *com){}virtual Compoment* findChild(int index){ return nullptr; }virtual Iterator<Compoment*>* createIterator(){}
};
class Leaf : public Compoment{
public:Leaf(int num) : num(num) {}~Leaf(){ std::cout << "~Leaf()" << num << endl;}virtual void operation() { cout << "Leaf::operation()" << num << endl; }void operation1(){ std::cout << "Leaf::operation1()" << num << std::endl; }Iterator<Compoment*>* createIterator(){return new NullIterator<Compoment*>();}
private:int num;
};
class Composite : public Compoment{
public:Composite(){}~Composite(){std::cout << "~Composite()" << std::endl;}void operation(){std::cout << "Composite::operation()" << std::endl;for(int i = 0; i < coms.size(); i ++ ){coms[i]->operation();}}void operation1(){std::cout << "Composite::operation1()" << std::endl;}bool isComposite(){ return true; }void add(Compoment *com){ coms.push_back(com); }Compoment* findChild(int index){if(index < 0 || index >= coms.size()){return nullptr;}return coms[index];}Iterator<Compoment*>* createIterator(){return new CompositeIterator<Compoment*>(coms.createIterator());}
private:newVector<Compoment*> coms;
};void doCompositePattern(){std::cout << "-----------com1->operation()-----------" << std::endl;Compoment *com1 = new Composite();com1->add(new Leaf(1));com1->add(new Leaf(2));com1->add(new Leaf(3));com1->operation();std::cout << "-----------com2->operation()-----------" << std::endl;Compoment *com2 = new Composite();com2->add(new Leaf(4));com2->add(com1);com2->add(com1);com1->add(new Leaf(11));com2->operation();std::cout << "\n-----------iterator-----------" << std::endl;Iterator<Compoment*>* iterator = com2->createIterator();while(iterator->hasNext()){iterator->next()->operation1();}
}int main(){doCompositePattern();return 0;
}

 参考

​​​​​​​​​​​​​​C++设计模式——组合模式(composite pattern)_c++ 设计模式组合-CSDN博客

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

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

相关文章

《绝地求生大逃杀》怎么买衣服 Steam商店服装购买方法

《绝地求生大逃杀》怎么买衣服&#xff1f;游戏中好看的服装有不少&#xff0c;大家可能开箱并没开出来&#xff0c;想买却不知具体的入手途径&#xff0c;今天闲游盒带来《绝地求生大逃杀》怎么买衣服 Steam商店服装购买方法&#xff0c;希望对各位有帮助。 打开Steam&#xf…

JavaEE进阶(6)SpringBoot 配置文件(作用、格式、properties配置文件说明、yml配置文件说明、验证码案例)

接上次博客&#xff1a;JavaEE进阶&#xff08;5&#xff09;Spring IoC&DI&#xff1a;入门、IoC介绍、IoC详解&#xff08;两种主要IoC容器实现、IoC和DI对对象的管理、Bean存储、方法注解 Bean)、DI详解&#xff1a;注入方式、总结-CSDN博客 目录 配置文件作用 Sprin…

thinkphp5实战之phpstudy v8环境搭建,解决Not Found找不到路径问题

引言 thinkphp以快速、简约的大道至简的思想广受欢迎&#xff0c;适合开发小型项目。本地环境下&#xff0c;phpstudy v8是一款比较优秀的集成环境软件。部署完项目后&#xff0c;访问的时候傻眼&#xff0c;报错。 解决方案 不要慌&#xff0c;这个是伪静态的原因。选择apach…

在 wsl-ubuntu 里通过 docker 启动 gpu-jupyter

在 wsl-ubuntu 里通过 docker 启动 gpu-jupyter 0. 背景1. 安装 docker-ce2. 安装 NVIDIA Container Toolkit3. 使用 nvidia-ctk 命令配置容器运行4. 通过 docker 运行 nvidia-smi5. 运行 gpu-jupyter6. 访问 gpu-jupyter7. 测试 gpu-jupyter 是否可以访问 cuda 0. 背景 今天突…

i18n多国语言Internationalization的动态实现

一、数据动态的更新 在上一篇i18n多国语言Internationalization的实现-CSDN博客&#xff0c;可能会遇到一个问题&#xff0c;我们在进行英文或中文切换时&#xff0c;并没有办法对当前的数据进行动态的更新。指的是什么意思呢&#xff1f;当前app.js当中一个组件内容&#xff…

Go语言学习笔记:基础语法和类型

Go语言学习笔记&#xff1a;基础语法和类型 目录 Go语言学习笔记&#xff1a;基础语法和类型学习路线前言变量声明常量数据类型布尔型&#xff08;Boolean&#xff09;整型&#xff08;Integer&#xff09;浮点型&#xff08;Floating point&#xff09;复数型&#xff08;Comp…

LeetCode.2765. 最长交替子数组

题目 2765. 最长交替子数组 分析 为了得到数组 nums 中的最长交替子数组的长度&#xff0c;需要分别计算以每个下标结尾的最长交替子数组的长度。为了方便处理&#xff0c;计算过程中需要考虑长度等于 1 的最长交替子数组&#xff0c;再返回结果时判断最长交替子数组的长度…

【代码整理】COCO格式数据集画框

可以用于排查数据集转化后可能出现的坐标错误&#xff0c;类别不对齐等需要可视化才能发现的问题 import部分 from pycocotools.coco import COCO import numpy as np import os from PIL import Image from matplotlib.collections import PatchCollection from matplotlib.…

详细分析Java中的Date类以及格式转换

目录 前言1. 基本知识2. 格式化输出3. 格式转换 前言 记录这篇文章的缘由&#xff0c;主要是涉及一个格式转换&#xff0c;对此深挖了这个类 在Java中&#xff0c;Date类是用于表示日期和时间的类。 位于java.util包中&#xff0c;是Java平台中处理日期和时间的基本类之一。…

路由器结构

路由器是连接互联网的设备&#xff0c;本文主要描述路由器的结构组成。 如上所示&#xff0c;OSI&#xff08;Open System Interconnect&#xff09;开放系统互联参考模型是互联网架构的标准协议栈&#xff0c;由ISO标准组织制定。自底向上&#xff0c;互联网架构分为7层&#…

服务器与Ajax

1.初识Ajax Asynchronous JavaScript and XML&#xff08;异步的 JavaScript 和 XML&#xff09;。 术语ajax最早产生于2005年&#xff0c;Ajax表示Asynchronous JavaScript and XML(异步JavaScript和XML)&#xff0c;但是它不是像HTML、JavaScript或CSS这样的一种“正式的”技…

Docker镜像操作

镜像名称 镜名称一般分两部分组成&#xff1a;[repository]:[tag]。 在没有指定tag时&#xff0c;默认是latest&#xff0c;代表最新版本的镜像。 这里的mysql就是repository&#xff0c;5.7就是tag&#xff0c;合一起就是镜像名称&#xff0c;代表5.7版本的MySQL镜像。 镜像…

YOLOv8改进 | 损失函数篇 | QualityFocalLoss质量焦点损失(含代码 + 详细修改教程)

一、本文介绍 本文给大家带来的改进机制是QualityFocalLoss,其是一种CLS分类损失函数,它的主要创新是将目标的定位质量(如边界框与真实对象的重叠度量,例如IoU得分)直接融合到分类损失中,形成一个联合表示。这种方法能够解决传统目标检测中分类与定位任务之间存在的不一…

Sentinel限流规则支持流控效果

流控效果是指请求达到流控阈值时应该采取的措施&#xff0c;包括三种&#xff1a; 1.快速失败&#xff1a;达到阈值后&#xff0c;新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。 2.warm up&#xff1a;预热模式&#xff0c;对超出阈值的请求同样是拒绝并抛…

风二西CTF流量题大集合-刷题笔记|NSSCTF流量题(1)

2.[鹤城杯 2021]流量分析 flag{w1reshARK_ez_1sntit} 3.[CISCN 2023 初赛]被加密的生产流量 c1f_fi1g_1000 4.[GKCTF 2021]签到 flag{Welc0me_GkC4F_m1siCCCCCC!} 5.[闽盾杯 2021]Modbus的秘密 flag{HeiDun_2021_JingSai} 6.[LitCTF 2023]easy_shark 7.[CISCN 2022 初赛]ez…

opencv#29 图像噪声的产生

在上一节的图像卷积我们了解到图像卷积可以用于去除图像中的噪声&#xff0c;那么对于现实生活中每一张采集到的图像都会包含噪声&#xff0c;也就是我们通过相机无法得到不包含噪声的图像&#xff0c;如果我想衡量噪声去除能力的强弱&#xff0c;就必须在一张不含噪声的图像中…

瑞_力扣LeetCode_104. 二叉树的最大深度

文章目录 题目 104. 二叉树的最大深度题解后序遍历 递归实现后序遍历 迭代实现层序遍历 &#x1f64a; 前言&#xff1a;本文章为瑞_系列专栏之《刷题》的力扣LeetCode系列&#xff0c;主要以力扣LeetCode网的题进行解析与分享。本文仅供大家交流、学习及研究使用&#xff0c;禁…

Armv8-M的TrustZone技术之内存属性单元

如果处理器包含Armv8-M安全扩展&#xff0c;则内存区域的安全状态由内部安全属性单元&#xff08;SAU&#xff0c;Secure Attribution Unit&#xff09;或外部实现定义的属性单元&#xff08;IDAU&#xff0c;Implementation Defined Attribution Unit&#xff09;的组合控制。…

机器学习实验报告——APRIORI算法

目录 一、算法介绍 1.1算法背景 1.2算法引入 1.3算法假设 1.4算法基本概念介绍 1.4.1关联规则 1.4.2支持度 1.4.3置信度 1.4.4频繁项集 1.4.5项目 1.4.6提升度 二、算法原理 2.1算法思想 2.2Apriori算法产生频繁项集 2.3Apriori算法的基本步骤 2.4关联分析 三、算法实现 3.1 Ap…

深度学习(5)---自注意力机制

文章目录 1. 输入与输出2. Self-attention2.1 介绍2.2 运作过程2.3 矩阵相乘理解运作过程 3. 位置编码4. Truncated Self-attention4.1 概述4.2 和CNN对比4.3 和RNN对比 1. 输入与输出 1. 一般情况下在简单模型中我们输入一个向量&#xff0c;输出结果可能是一个数值或者一个类…