当一些代码具有相似的逻辑,完成相似的功能,我们就没有必要每次实现这样的功能的时候都把代码重写一遍。可以把这样有相似逻辑的代码抽象出来,固化下来,以后需要使用这样的功能时,直接把代码拿来用。将代码固化下来之后有以下几点好处:
(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;
}