容器的主要职责有两个:存放元素和浏览元素。根据单一职责原则(SRP)要将二者分开,于是将浏览功能打包封装就有了迭代器。
用迭代器封装对动态数组的遍历:

1
2
{《HeadFirst设计模式》之迭代器模式 }
3
{ 容器中的元素类 }
4
{ 编译工具:Delphi7.0 }
5
{ E-Mail :guzh-0417@163.com }
6
7
unit uItem;
8
9
interface
10
11
type
12
TMenuItem = class(TObject)
13
private
14
FName: String;
15
FDescription: String;
16
FVegetarian : Boolean;
17
FPrice: Double;
18
public
19
constructor Create(aName, aDescription: String;
20
aVegetarian : Boolean;
21
aPrice: Double);
22
function GetName: String;
23
function GetDescription: String;
24
function GetPrice: Double;
25
function IsVegetarian: Boolean;
26
end;
27
28
implementation
29
30
{ TMenuItem }
31
32
constructor TMenuItem.Create(aName, aDescription: String;
33
aVegetarian: Boolean;
34
aPrice: Double);
35
begin
36
FName := aName;
37
FDescription := aDescription;
38
FVegetarian := aVegetarian;
39
FPrice := aPrice;
40
end;
41
42
function TMenuItem.GetDescription: String;
43
begin
44
Result := FDescription;
45
end;
46
47
function TMenuItem.GetName: String;
48
begin
49
Result := FName;
50
end;
51
52
function TMenuItem.GetPrice: Double;
53
begin
54
Result := FPrice;
55
end;
56
57
function TMenuItem.IsVegetarian: Boolean;
58
begin
59
Result := FVegetarian;
60
end;
61
62
end.

1
2
{《HeadFirst设计模式》之迭代器模式 }
3
{ 迭代器:封装对容器的遍历 }
4
{ 编译工具:Delphi7.0 }
5
{ E-Mail :guzh-0417@163.com }
6
7
unit uIterator;
8
9
interface
10
11
uses
12
uItem;
13
14
type
15
TMenuItems = array of TMenuItem;
16
17
TIterator = class(TObject)
18
public
19
function HasNext: Boolean; virtual; abstract;
20
function Next : TObject; virtual; abstract;
21
end;
22
23
TDinerMenuIterator = class(TIterator)
24
private
25
FMenuItem : TMenuItem;
26
FMenuItems: TMenuItems;
27
FPosition : Integer;
28
public
29
constructor Create(MenuItems: TMenuItems);
30
function HasNext: Boolean; override;
31
function Next : TObject; override;
32
end;
33
34
implementation
35
36
{ TDinerMenuIterator }
37
38
constructor TDinerMenuIterator.Create(MenuItems: TMenuItems);
39
begin
40
FMenuItems := MenuItems;
41
end;
42
43
function TDinerMenuIterator.HasNext: Boolean;
44
begin
45
if (FPosition < Length(FMenuItems)) and (FMenuItems[FPosition] <> nil) then
46
Result := True
47
else
48
Result := False;
49
end;
50
51
function TDinerMenuIterator.Next: TObject;
52
begin
53
FMenuItem := FMenuItems[FPosition];
54
FPosition := FPosition + 1 ;
55
Result := FMenuItem;
56
end;
57
58
end.

1
2
{《HeadFirst设计模式》之迭代器模式 }
3
{ 容器类及其用户: Waitress }
4
{ 编译工具:Delphi7.0 }
5
{ E-Mail :guzh-0417@163.com }
6
7
unit uAggregate;
8
9
interface
10
11
uses
12
SysUtils, uItem, uIterator;
13
14
type
15
TMenu = class(TObject)
16
public
17
function CreateIterator: TIterator; virtual; abstract;
18
end;
19
20
TDinerMenu = class(TMenu)
21
private
22
FMenuItem : TMenuItem;
23
FMenuItems: TMenuItems;
24
FNumberOfItems: Integer;
25
public
26
constructor Create;
27
destructor Destroy; override;
28
procedure AddItem(aName, aDescription: String; aVegetarian: Boolean;
29
aPrice: Double);
30
function CreateIterator: TIterator; override;
31
end;
32
33
TWaitress = class(TObject)
34
private
35
FMenuItem : TMenuItem;
36
FDinerMenu: TDinerMenu;
37
DinerIterator: TIterator;
38
public
39
constructor Create(aDinerMenu: TDinerMenu);
40
procedure PrintMenu; overload;
41
procedure PrintMenu(aIterator: TIterator); overload;
42
end;
43
44
implementation
45
46
const
47
MAX_TIMES = 6;
48
49
{ TDinerMenu }
50
51
procedure TDinerMenu.AddItem(aName, aDescription: String; aVegetarian: Boolean;
52
aPrice: Double);
53
begin
54
FMenuItem := TMenuItem.Create(aName, aDescription, aVegetarian, aPrice);
55
if FNumberOfItems >= MAX_TIMES then
56
Writeln('Sorry, menu is full! Can''t add item to menu')
57
else
58
begin
59
FMenuItems[FNumberOfItems] := FMenuItem;
60
FNumberOfItems := FNumberOfItems + 1;
61
end;
62
end;
63
64
constructor TDinerMenu.Create;
65
begin
66
SetLength(FMenuItems, MAX_TIMES);
67
68
AddItem('Vegetarian BLT',
69
'Fakin Bacon with lettuce & tomato on whole Wheat', True, 2.99);
70
AddItem('BLT',
71
'Bacon with lettuce & tomato on whole Wheat', False, 2.99);
72
AddItem('Soup of the day',
73
'Soup of the day, with a side of potato salad', False, 3.29);
74
AddItem('Hotdog',
75
'A hot dog, with saurkraut, relish, onions, topped with cheese',
76
False, 3.05);
77
AddItem('Steamed Veggies and Brown Rice',
78
'Steamed vegetables over brown rice', True, 3.99);
79
AddItem('Pasta',
80
'Spaghetti with Marinara Sauce, and a slice of sourdough bread', True,
81
3.89);
82
end;
83
84
destructor TDinerMenu.Destroy;
85
begin
86
FreeAndNil(FMenuItem);
87
inherited;
88
end;
89
90
function TDinerMenu.CreateIterator: TIterator;
91
begin
92
Result := TDinerMenuIterator.Create(FMenuItems);
93
end;
94
95
{ TWaitress }
96
97
constructor TWaitress.Create(aDinerMenu: TDinerMenu);
98
begin
99
FDinerMenu := aDinerMenu;
100
end;
101
102
procedure TWaitress.PrintMenu;
103
begin
104
try
105
DinerIterator := FDinerMenu.CreateIterator;
106
Writeln('MENU');
107
Writeln('----');
108
Writeln('BREAKFAST');
109
Writeln;
110
PrintMenu(DinerIterator);
111
finally
112
FreeAndNil(DinerIterator);
113
end;
114
end;
115
116
procedure TWaitress.PrintMenu(aIterator: TIterator);
117
begin
118
while (aIterator.HasNext) do
119
begin
120
FMenuItem := (aIterator.Next) as TMenuItem;
121
Writeln(FMenuItem.GetName + ',');
122
Writeln(FMenuItem.GetPrice, ' -- ');
123
Writeln(FMenuItem.GetDescription);
124
end;
125
end;
126
127
end.

1
2
{《HeadFirst设计模式》之迭代器模式 }
3
{ 客户端 }
4
{ 编译工具:Delphi7.0 }
5
{ E-Mail :guzh-0417@163.com }
6
7
program pMenuTestDrive;
8
9
{$APPTYPE CONSOLE}
10
11
uses
12
SysUtils,
13
uItem in 'uItem.pas',
14
uAggregate in 'uAggregate.pas',
15
uIterator in 'uIterator.pas';
16
17
var
18
DinerMenu: TDinerMenu;
19
Waitress : TWaitress;
20
21
begin
22
DinerMenu := TDinerMenu.Create;
23
Waitress := TWaitress.Create(DinerMenu);
24
Waitress.PrintMenu;
25
26
FreeAndNil(DinerMenu);
27
FreeAndNil(Waitress);
28
Readln;
29
end.
运行结果:

特别感谢:在实现上面示例时,遇到动态数组做参数的问题。感谢盒子论坛里的ZuoBaoQuan兄出手相助!