行为型 迭代器模式

简介: 行为型 迭代器模式

迭代器的作用:遍历某一类相同元素的集合。

迭代器模式属于 行为型设计模式。

迭代器的思路: 在不改变底层元素的前提下,按照某种方式遍历集合中元素的值。

迭代器的实现:

1:前提: 需要一个集合元素类,一个集合类,需要一个迭代器类

2:迭代器中可以获取到集合类的对象,对该对象进行接口封装。

3:如何扩展迭代器模型: 可以用模板模型进行扩展


1: 《图解设计模式》中遍历书架中的书本为例子,UML图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XahJ4p33-1627281881798)(…\md文档相关图片\迭代器模式实例UML图.png)]

对上面的这幅图做进一步的说明,

  • Aggregate表示集合的接口,书架实现该接口,所以书架必须要有迭代器的方法;
  • Iterator表示集合的迭代器的接口,书架的迭代器实现它,需要用到书架具体对象调用相关的方法;
    需要说明的是,此处的迭代器只有一种前向的迭代器,也可以定义后向遍历的迭代器。

认识: Aggregate和Iterator是抽象类,虚接口;

Bookshelf是实际的集合类的实现类。 ==》初始化迭代器类

BookShelfIterator 是对应bookshelf集合类对应的具体迭代器封装实现类。 ==》初始化时要传入集合类的对象

2:根据上文的理解,初步尝试实现迭代器的demo代码(C++):

//1:实现集合中单个元素的类
//2:实现迭代器的类,具体迭代器的类可以操作对应的集合类,用到集合类中的相关遍历方法
//如何实现迭代器中可以用到集合类对象的接口,需要传递
//3:实现集合的类,包含创建迭代器接口。 
//简单的一个集合类,然后创建一个迭代器类,通过迭代器类控制集合的遍历访问集合中元素。
#include <iostream>
#include <vector>
using namespace std;
class TestIterator;
class TestVector{
public:
  //构造和析构
  TestVector():m_itr(nullptr), count(0)
  {}
  ~TestVector() {
    if(m_itr != nullptr)
    {
      delete m_itr;
      m_itr = nullptr;
    }
  }
  //类本身的方法  插入元素和获取元素
  void push(int d) {
    m_testvector.push_back(d);
    count++;
  }
  void pop()
  {
    m_testvector.pop_back();
    count--;
  }
  int getCount()
  {
    return count;
  }
  int getData(int d)
  {
    if(d < count)
    {
      return m_testvector[d];
    }
    return -1;
  }
  //这里定义创建迭代器的方法,通过迭代器控制数组元素的访问
  TestIterator * CreateTestIterator()
  {
    if(m_itr == nullptr)
    {
      m_itr = new TestIterator(this);
    }
    return m_itr;
  }
private:
  vector<int> m_testvector;
  TestIterator * m_itr; //这里为了对应释放
  int count;
};
//通过迭代器类调用对应的方法访问集合元素 这里用下标控制访问
class TestIterator
{
public:
  //要操作的集合的类和集合下标
  TestIterator(TestVector * ts):m_ts(ts), curr(0)
  {}
  ~TestIterator() {}
  //判断是否有下一个元素
  bool HasNext()
  {
    if(curr >= m_ts->getCount())
    {
      return false;
    }
    return true;
  }
  //返回的其实是集合类中迭代器下一个元素
  int Next()
  {
    int data = m_ts->getData(curr);
    curr++;
    return data;
  }
  //重置节点的信息
  void reset()
  {
    curr=0;
  }
private:
  TestVector* m_ts;
  int curr;
};
int main()
{
  //创建一个集合类 并塞入相关数据
  TestVector * test = new TestVector();
  test->push(5);
  test->push(8);
  test->push(6);
  test->push(7);
  test->push(3);
  test->push(2);
  cout<<"count:"<<test->getCount()<<endl;
  TestIterator *itr = test->CreateTestIterator();
  int num = 0;
  //这里的元素是一个int,所以直接打印,可以有其他类型
  while(itr->HasNext())
  {
    cout<<" num "<<num <<"is "<<itr->Next()<<endl;
    num ++;
  }
  for(int i=0;i<test->getCount(); i++)
  {
    cout<<" i "<<i<<" is" <<test->getData(i)<<endl;
  }
  if(test != nullptr)
  {
    delete test;
    test= nullptr;
  }
  return 0;
}

注意: 发现上述代码因为两个类相互引用,而无法编译通过。

3:思考解决引用编译不过的问题

可以用虚基函数来处理。

可以用C++模板定义来规避,直接用类型替代。

//上面的demo发现编译不通过,是类与类之间相关引用的原因,所以这里需要一个中间类来实现
//迭代器测试类初始化要用到 集合类,这里构造一个集合类的基类,实现迭代器的初始化测试
//集合类要用到迭代器类去做相关初始化 同样需要构造一个迭代器基础类,来供集合类接口调用
#include <iostream>
#include <vector>
using namespace std;
class baseIterator{
public:
  virtual ~baseIterator() = default;
  virtual bool HasNext() = 0;
  virtual int Next() = 0;
  virtual void reset() = 0;
};
//包含必要的集合类的方法,通过传入该对象实现迭代器的调用
class baseTestIterator{
public:
  virtual ~baseTestIterator() = default;
  virtual baseIterator * CreateTestIterator()= 0;
  virtual int getCount() = 0;
  virtual int getData(int d) = 0;
};
class TestIterator: public baseIterator
{
public:
  //要操作的集合的类和集合下标
  TestIterator(baseTestIterator * ts):m_ts(ts), curr(0)
  {}
  ~TestIterator() {}
  //判断是否有下一个元素
  bool HasNext()
  {
    if(curr >= m_ts->getCount())
    {
      return false;
    }
    return true;
  }
  //返回的其实是集合类中迭代器下一个元素
  int Next()
  {
    int data = m_ts->getData(curr);
    curr++;
    return data;
  }
  //重置节点的信息
  void reset()
  {
    curr=0;
  }
private:
  baseTestIterator* m_ts;
  int curr;
};
class TestVector: public baseTestIterator{
public:
  //构造和析构
  TestVector():m_itr(nullptr), count(0)
  {}
  ~TestVector() {
    if(m_itr != nullptr)
    {
      delete m_itr;
      m_itr = nullptr;
    }
  }
  //类本身的方法  插入元素和获取元素
  void push(int d) {
    m_testvector.push_back(d);
    count++;
  }
  void pop()
  {
    m_testvector.pop_back();
    count--;
  }
  int getCount()
  {
    return count;
  }
  int getData(int d)
  {
    if(d < count)
    {
      return m_testvector[d];
    }
    return -1;
  }
  //这里定义创建迭代器的方法,通过迭代器控制数组元素的访问
  baseIterator * CreateTestIterator()
  {
    if(m_itr == nullptr)
    {
      m_itr = new TestIterator(this);
    }
    return m_itr;
  }
private:
  vector<int> m_testvector;
  baseIterator * m_itr; //这里为了对应释放
  int count;
};
int main()
{
  //创建一个集合类 并塞入相关数据
  TestVector * test = new TestVector();
  test->push(5);
  test->push(8);
  test->push(6);
  test->push(7);
  test->push(3);
  test->push(2);
  cout<<"count:"<<test->getCount()<<endl;
  baseIterator *itr = test->CreateTestIterator();
  int num = 0;
  //这里的元素是一个int,所以直接打印,可以有其他类型
  while(itr->HasNext())
  {
    cout<<" num "<<num <<"is "<<itr->Next()<<endl;
    num ++;
  }
  for(int i=0;i<test->getCount(); i++)
  {
    cout<<" i "<<i<<" is " <<test->getData(i)<<endl;
  }
  if(test != nullptr)
  {
    delete test;
    test= nullptr;
  }
  return 0;
}
//C++中相关集合类数据结构的迭代器实现方式类似,只是增加了模板定义,next的处理用指针地址+1代替 模板机制代替了虚基函数处理引用的问题
目录
相关文章
|
编解码 开发工具 C++
【软件设计师备考 专题 】多媒体应用开发过程(一)
【软件设计师备考 专题 】多媒体应用开发过程
273 0
|
敏捷开发 监控 容灾
阿里巴巴DevOps实践指南(二十二)| 发布策略
DevOps 追求更短的迭代周期、更高频的发布。但发布的次数越多,引入故障的可能性就越大。更多的故障将会降低服务的可用性,进而影响到客户体验。所以,为了保证服务质量,守好发布这个最后一道关,阿里逐步发展出了适应 DevOps 要求的发布策略。
阿里巴巴DevOps实践指南(二十二)| 发布策略
|
存储 数据采集 人工智能
如何设计一个监控平台(上篇)
在大型分布式微服务场景下,各个服务版本快速迭代,各类业务规模不断膨胀,同时监控的场景也在不断的发生变化,线上故障随时可能发生,各个平台错综复杂,如何保证线上服务稳定运行,同时提升运维效率,降低运维成本成了监控平台的挑战。
如何设计一个监控平台(上篇)
|
人工智能 Cloud Native Serverless
阿里云爸爸发福利!DeepSeek-R1满血版深度体验,4种部署攻略+隐藏羊毛大公开💎
本文介绍了四种部署DeepSeek-R1模型的方式:基于百炼调用满血版API、基于PAI部署、基于函数计算部署和基于GPU云服务器部署。每种方式各有优劣,适合不同需求的用户。其中,基于百炼调用满血版API无需部署,提供满血版模型和100万免费Token,适合快速体验;基于PAI部署适合需要微调模型的用户;基于函数计算部署提供WEB交互界面;基于GPU云服务器部署则适合技术能力强、有硬件资源的用户。方案还提供了免费试用入口和实践体验总结,帮助开发者更好地理解和使用DeepSeek-R1模型。
582 62
|
存储 NoSQL Redis
Redis 配置
10月更文挑战第14天
284 1
|
机器学习/深度学习 人工智能
IBM推出创新框架用“黑盒”方式,评估大模型的输出
【7月更文挑战第17天】IBM研发的创新框架以“黑盒”方法评估大模型输出的可信度,通过观察输入和输出,不涉及模型内部。采用逻辑回归模型,基于四个特征(输出长度、多样性、一致性和新颖性)来估计可信度。在多个数据集上测试,显示优于其他“黑盒”方法,且具有可解释性。但仅适用于可访问的模型,可能忽略内部细节,不适用于所有场景。[[arXiv:2406.04370](https://arxiv.org/abs/2406.04370)]
330 4
|
供应链 区块链
探索区块链技术在供应链管理中的应用与挑战
本文深入探讨了区块链技术在现代供应链管理中的创新应用及其面临的挑战。通过分析区块链的去中心化特性、不可篡改性以及透明度,阐述了如何利用这一技术优化供应链流程,提高数据共享的安全性与效率。同时,文章也指出了实施过程中的技术难题、成本考量及法规限制等挑战,为读者提供了对区块链技术在供应链领域应用前景的全面认识。
|
机器人 Java 测试技术
《手把手教你》系列技巧篇(六十)-java+ selenium自动化测试 - 截图三剑客 -中篇(详细教程)
【6月更文挑战第1天】本文介绍了使用Java和Selenium进行自动化测试时的另一种截图方法,即利用Robot类实现全屏截图。Robot类能够捕获屏幕上的所有内容,包括任务栏和浏览器元素。测试场景包括访问指定网站、调用截图方法和保存截图。示例代码展示了如何使用Robot创建全屏截图并保存到特定文件夹。在运行代码前,需确保指定的保存路径存在,否则会报错。
260 4
|
存储 JavaScript 关系型数据库
中国国家统计局发布的行政区划数据-nodejs抓取
由于国家的行政区划每年都有变化,所以经常需要更新最新的数据,这里提供一个nodejs版本mysql数据存储的抓取示例。
中国国家统计局发布的行政区划数据-nodejs抓取
|
前端开发 NoSQL 数据库
设计 QQ、微信等第三方账号登陆
设计 QQ、微信等第三方账号登陆
265 0
设计 QQ、微信等第三方账号登陆