设计模式-迭代器模式

Iterator

迭代器模式是在不暴露集合底层数据格式的情况下对集合进行遍历

  • 当集合/对象内部存在复杂的数据结构时,出于安全性或便利性考虑采用该模式
  • 简单集合会增加代码复杂性,特殊集合可能效率不如直接遍历

例如复制容器

1
2
3
4
5
6
// direct
for (int i = 0; i < vec.size(); ++i) {
vec2.push_back(vec[i]);
}
// iterator
std::copy(vec.begin(), vec.end(), std::back_inserter(vec2));

使用迭代器模式时,格式更加简洁,且无需关注容器内部数据结构,更具灵活性和通用性

使用场景

CPP

基本结构

Member FullName Description
聚合接口 Aggregate 定义遍历的集合
具体聚合类 ConcreteAggregate 维护集合类
迭代器接口 Iterator 定义遍历接口
具体迭代器类 ConcreteIterator 实现迭代器对集合进行遍历

UML结构图

实现步骤

  1. 定义迭代器接口
1
2
3
4
5
6
7
class Iterator {
public:
virtual bool HasNext() const = 0;
virtual void Next() = 0;
virtual int CurrentItem() const = 0;
virtual ~Iterator() = default;
};
  1. 定义聚合接口 (包含迭代器)
1
2
3
4
5
class Aggregate {
public:
virtual Iterator* CreateIterator() const = 0;
virtual ~Aggregate() = default;
};
  1. 定义具体聚合类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class IntCollection : public Aggregate {
private:
int data[100];
int count;

public:
void IntCollection::AddItem(int item) {
if (count < 100) { // 限制最大容量
data[count++] = item;
}
}

int IntCollection::GetItem(int index) const {
return data[index];
}

int IntCollection::Count() const {
return count;
}

Iterator* IntCollection::CreateIterator() const {
return new IntIterator(*this);
}
};
  1. 定义具体迭代器类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class IntIterator : public Iterator {
private:
const IntCollection& collection;
int currentIndex;

public:
IntIterator(const IntCollection& collection)
: collection(collection), currentIndex(0) {}

bool IntIterator::HasNext() const {
return currentIndex < collection.Count();
}

void IntIterator::Next() {
if (HasNext()) {
currentIndex++;
}
}

int IntIterator::CurrentItem() const {
if (currentIndex < collection.Count()) {
return collection.GetItem(currentIndex);
}
return 0;
}
};
  1. 使用迭代器
1
2
3
4
5
6
7
8
9
10
11
IntCollection collection;
collection.AddItem(10);
collection.AddItem(20);
collection.AddItem(30);

Iterator* iterator = collection.CreateIterator();
while (iterator->HasNext()) {
std::cout << iterator->CurrentItem() << std::endl;
iterator->Next();
}
delete iterator;

Fortran

fortran 实现迭代器模式主要问题在于迭代器和容器包含相互的指针,该过程难以实现,虽然通过 复制 能够完成数据传递,但会占用额外空间

一种可能的方案是将 create_iterator 放在迭代器类下,将 Aggregate 实例对象指针作为输入参数

代码存在段错误,需要进一步调试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
module iterator_module
implicit none
private

type, public :: int_collection
integer, dimension(:), allocatable :: data
end type int_collection

type, public :: int_iterator
class(int_collection), pointer :: collection => null()
integer :: index = 0
contains
procedure, public :: create_iterator
procedure, public :: has_next
procedure, public :: next
end type int_iterator

contains

subroutine create_iterator(this, aggregate)
class(int_iterator), intent(inout) :: this
type(int_collection), pointer :: aggregate

this%collection => aggregate
this%index = 0
end subroutine create_iterator

logical function has_next(this)
class(int_iterator), intent(in) :: this
integer :: n
n = size(this%collection%data)
has_next = this%index < n
end function has_next

integer function next(this)
class(int_iterator), intent(inout) :: this
integer :: current
integer :: n
n = size(this%collection%data)
if (this%index >= n) then
stop "Error: No more elements"
end if
current = this%collection%data(this%index + 1)
this%index = this%index + 1
next = current
end function next

end module iterator_module

program main
use iterator_module
implicit none

type(int_collection), pointer :: collection => null()
integer :: data(5) = [1, 2, 3, 4, 5]
type(int_iterator), pointer :: iterator

allocate(collection)
collection%data = data

call iterator%create_iterator(collection)

do while (iterator%has_next())
print *, iterator%next()
end do

deallocate(iterator)
deallocate(collection)
end program main

Reference

refactoringguru | 迭代器模式
扣丁梦想家 | 设计模式教程:迭代器模式(Iterator Pattern)
supdriver | 设计模式的C++实现(4)——迭代器Iterator

0%