设计模式:迭代器模式
当一些代码具有相似的逻辑,完成相似的功能,我们就没有必要每次实现这样的功能的时候都把代码重写一遍。可以把这样有相似逻辑的代码抽象出来,固化下来,以后需要使用这样的功能时,直接把代码拿来用。将代码固化下来之后有以下几点好处:
(1)提高了复用性
代码固化下来之后,使用这样的功能时直接拿来使用。
(2)对修改关闭
代码固化下来之后,修改的频率就很低了。比如编程语言标准库中的代码,修改的频率是比较低的。
针对我们写代码的很多场景,很多种用法,进行归纳总结,固化下来的一些编码的规范,这就是设计模式。这就给我们提供了一些写代码的思路,即使没有学习过设计模式,那么在写代码的时候,也可以想代码实现的是不是一个独立的、高内聚的功能,这样的代码是不是可以抽象出来,提高复用性。即使我们不知道一些设计模式,也能写出高内聚、低耦合,对修改关闭、对扩展开放,可维护性好、可扩展性好的代码。
迭代器模式针对的是遍历一个数据结构的场景。常见的基本数据结构有数组、链表、二叉树,另外还有map、set等。对于数组和链表来说,这种数据结构比较简单,遍历操作比较简单,我们可以直接使用for循环或者while循环来遍历。但是对于一些复杂的数据结构,比如二叉树、map、set等,遍历操作就比较复杂,如果每次遍历这样的数据结构都要自己写遍历代码,这样的工作效率是比较低下的。所以这就是设计模式的意义。对于常见的语言来说,这些常用的数据结构和迭代器,都在语言的标准库中实现了,在实际工作中,我们并不需要自己实现一个迭代器。
对于线性数据结构来说,迭代器模式,和直接使用下边的方式,复杂成都市差不多的,但是对于复杂的数据类型,比如map或者set,迭代器就有用了。
最简迭代器
(1)实现了Array数组类
①在构造函数中需要传入数组的长度
②重载了[]操作符
(2)实现了Array的迭代器类ArrayIterator
①重载了++操作符,用于移动迭代器
②实现了begin方法,用于获取数组的第一个元素
③实现了end方法用于判断迭代器是不是遍历结束
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <memory>
template <typename T>
class ArrayIterator {
public:
ArrayIterator(T* ptr, const int size)
: ptr_{ptr}, size_{size}, index_{0} {}
T *operator++() {
index_++;
return ptr_ + index_;
}
T *begin() {
return ptr_;
}
T *end() {
return ptr_ + size_;
}
private:
T *ptr_;
const int size_;
int index_;
};
template <typename T>
class Array {
public:
Array(const int size) : size_{size} {
if (size_ <= 0) {
throw "invalid argument";
}
ptr_ = (T *)malloc(size_ * sizeof(T));
if (ptr_ == nullptr) {
throw "malloc failed";
}
}
T& operator[](const int index) {
if (index < 0 || index >= size_) {
throw "invalid argument";
}
printf("\nptr=%p\n", ptr_ + index);
return *(ptr_ + index);
}
std::unique_ptr<ArrayIterator<T>> iterator() {
return std::move(std::make_unique<ArrayIterator<T>>(ptr_, size_));
}
int size() {
return size_;
}
private:
T *ptr_;
const int size_;
};
int main() {
Array<int> a(8);
std::unique_ptr<ArrayIterator<int>> it = a.iterator();
for (int i = 0; i < 8; i++) {
a[i] = i * i;
}
auto itt = it->begin();
for(; itt != it->end(); itt++) {
std::cout << "val=" << *itt << std::endl;
}
return 0;
}