(十)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,一经查实,立即删除!

相关文章

Golang 通过开源库 go-redis 操作 NoSQL 缓存服务器

前置条件&#xff1a; 1、导入库&#xff1a; import ( "github.com/go-redis/redis/v8" ) 2、搭建哨兵模式集群 具体可以百度、谷歌搜索&#xff0c;网上现成配置教程太多了&#xff0c;不行还可以搜教程视频&#xff0c;跟着视频博主一步一个慢动作&#xff0…

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

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

Oracle中如何把整个表作为参数传递

当然可以&#xff01;在Oracle中&#xff0c;你可以使用表类型的变量来传递表作为参数。首先&#xff0c;你需要创建一个表类型的变量&#xff0c;然后在存储过程或函数中声明这个变量。接下来&#xff0c;你可以将实际表的数据赋值给这个变量&#xff0c;并在存储过程或函数中…

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…

技巧--75. 颜色分类/medium 理解度C

75. 颜色分类 1、题目2、题目分析3、复杂度最优解代码示例4、适用场景 1、题目 给定一个大小为 n 的数组 nums &#xff0c;返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的&#xff0c;并且给定的数组总是存在多数元素。…

LeetCode刷题日记

LeetCode刷题日记 HashMap 第1题----两数之和 原题地址 [https://leetcode.cn/problems/two-sum/]: 解题思路&#xff1a; 将数组中每个元素通过两次遍历使两数之差target&#xff0c;最后由结果target得到对应数组下标。此时算法的时间复杂度为O(n^2)。故而放弃此方法。 由于…

Flink对接Kafka的topic数据消费offset设置参数

scan.startup.mode 是 Flink 中用于设置消费 Kafka topic 数据的起始 offset 的配置参数之一。 scan.startup.mode 可以设置为以下几种模式&#xff1a; earliest-offset&#xff1a;从最早的 offset 开始消费数据。latest-offset&#xff1a;从最新的 offset 开始消费数据。…

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

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

Kong关键概念 - 服务(Services)

服务&#xff08;Services&#xff09; 在Kong Gateway中&#xff0c;服务是代表外部上游&#xff08;upstream&#xff09;API或微服务的实体。例如&#xff0c;数据转换微服务、计费API等。 服务的主要属性是其URL。您可以使用一个字符串来指定URL&#xff0c;或者通过分别…

在 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. 背景 今天突…

Vue3的ref和reactive

目录 1、ref的基本使用 2、reactive的基本使用 3、ref操作dom 4、ref与reactive的异同 1、ref的基本使用 ref创建数据可以是基本类型也可以是引用类型 ref函数创建响应式数据&#xff0c;返回值是一个对象 模版中使用ref数据,省略.value&#xff0c;js代码中不能省略 获…

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这样的一种“正式的”技…

从零开始:Ubuntu Server中MySQL 8.0的安装与Django数据库配置详解

Ubuntu系统纯净安装MySQL8.0 1、安装Mysql8.0 sudo apt install mysql-server2、检查MySQL状态 sudo systemctl status mysql如下所示看见Active: active (running)说明mysql状态正常 ● mysql.service - MySQL Community ServerLoaded: loaded (/lib/systemd/system/mysql…

Docker镜像操作

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