示例:健壮的迭代器
说明:
一个健壮的迭代器(robustiterator)保证插入和删除操作不会干扰遍历,且不需拷贝该聚合。有许多方法来实现健壮的迭代器。其中大多数需要向这个聚合注册该迭代器。当插入或删除元素时,该聚合要么调整迭代器的内部状态,要么在内部的维护额外的信息以保证正确的遍历。
代码:
unit uObserver;
interface
uses classes;
type
TObserver = class;
TSubjectData = class
protected
FObs: TList;
FNotifyEnabled: Boolean;
procedure NotifyObserver;
procedure SetEnableNotify(AEnable: Boolean);
public
constructor Create;
destructor Destroy; override;
//---
procedure Attach(AObserver: TObserver);
procedure Detach(AObserver: TObserver);
procedure UpdateObserver;
//---
property NotifyEnabled: Boolean read FNotifyEnabled write SetEnableNotify;
end;
TObserver = class
protected
FSubjectData: TSubjectData;
public
constructor Create(ASubjectData: TSubjectData);
destructor Destroy; override;
//---
procedure Update; virtual;
end;
implementation
constructor TSubjectData.Create;
begin
FObs := TList.Create;
FNotifyEnabled := true;
end;
destructor TSubjectData.Destroy;
begin
FObs.Free;
end;
procedure TSubjectData.Attach(AObserver: TObserver);
begin
FObs.Add(AObserver);
end;
procedure TSubjectData.Detach(AObserver: TObserver);
begin
FObs.Remove(AObserver);
end;
procedure TSubjectData.NotifyObserver;
var
i: integer;
begin
for i := 0 to FObs.Count - 1 do
TObserver(FObs[i]).Update;
end;
procedure TSubjectData.UpdateObserver;
begin
NotifyObserver;
end;
procedure TSubjectData.SetEnableNotify(AEnable: Boolean);
begin
FNotifyEnabled := AEnable;
if FNotifyEnabled then NotifyObserver;
end;
constructor TObserver.Create(ASubjectData: TSubjectData);
begin
FSubjectData := ASubjectData;
FSubjectData.Attach(Self);
end;
destructor TObserver.Destroy;
begin
FSubjectData.Detach(Self);
//---
inherited;
end;
procedure TObserver.Update;
begin
end;
end.
unit uRobustIterator;
interface
uses
SysUtils, Classes, Dialogs, uObserver;
type
TAggregateState = (tsAdd, tsInsert, tsDelete);
TConcreteAggregate = class;
TIterator = class(TObserver)
public
procedure First(); virtual; abstract;
procedure Next(); virtual; abstract;
function IsDone(): Boolean; virtual; abstract;
function CurrentItem(): string; virtual; abstract;
end;
TConcreteIterator = class(TIterator)
private
FAggregate: TConcreteAggregate;
FCurrent: integer;
public
constructor Create(const Aggregate: TConcreteAggregate);
//---
procedure First(); override;
procedure Next(); override;
function IsDone(): Boolean; override;
function CurrentItem: string; override;
//---
procedure Update; override;
end;
TAggregate = class(TSubjectData)
public
function CreateIterator(): TIterator; virtual; abstract;
end;
TConcreteAggregate = class(TAggregate)
private
FList: TStringList;
FState: TAggregateState;
FIndex: Integer;
function GetCount: integer;
function GetItems(Index: integer): string;
public
constructor Create;
destructor Destroy; override;
//---
function CreateIterator: TIterator; override;
//---
procedure Add(s: string);
procedure Insert(Index: Integer; s: string);
procedure Delete(Index: Integer);
//---
property Count: integer read GetCount;
property Items[Index: integer]: string read GetItems; default;
end;
procedure Test;
implementation
procedure Test;
var
Aggregate: TConcreteAggregate;
AIterator: TIterator;
i:Integer;
begin
Aggregate := TConcreteAggregate.Create;
AIterator := Aggregate.CreateIterator;
try
with Aggregate do
begin
Add('111');
Add('222');
Add('333');
end;
//---
i := 0;
with AIterator do
begin
First;
while not IsDone do
begin
Inc(i);
if i = 2 then
Aggregate.Delete(1);
//---
ShowMessage(CurrentItem);
Next;
end;
end;
finally
AIterator.Free;
Aggregate.Free;
end;
end;
constructor TConcreteIterator.Create(const Aggregate: TConcreteAggregate);
begin
inherited Create(Aggregate);
//---
FAggregate := Aggregate;
FCurrent := 0;
end;
procedure TConcreteIterator.First;
begin
FCurrent := 0;
end;
procedure TConcreteIterator.Next;
begin
FCurrent := FCurrent + 1;
end;
function TConcreteIterator.IsDone: Boolean;
begin
Result := FCurrent >= FAggregate.Count;
end;
function TConcreteIterator.CurrentItem: string;
begin
if self.IsDone then
raise Exception.Create('Iterator Out Of Bounds');
//---
Result := FAggregate.Items[FCurrent];
end;
constructor TConcreteAggregate.Create;
begin
inherited;
//---
FList := TStringList.Create;
end;
destructor TConcreteAggregate.Destroy;
begin
FList.Free;
//---
inherited;
end;
function TConcreteAggregate.CreateIterator: TIterator;
begin
Result := TConcreteIterator.Create(self);
end;
function TConcreteAggregate.GetCount: integer;
begin
Result := FList.Count;
end;
function TConcreteAggregate.GetItems(Index: integer): string;
begin
Result := FList[Index];
end;
procedure TConcreteAggregate.Add(s: string);
begin
FList.Add(s);
//---
FState := tsAdd;
FIndex := FList.Count - 1;
//---
self.NotifyEnabled := True;
end;
procedure TConcreteIterator.Update;
begin
with FAggregate do
begin
case FState of
tsDelete:
begin
if FIndex < FCurrent then
FCurrent := FCurrent - 1;
end;
end;
end;
end;
procedure TConcreteAggregate.Delete(Index: Integer);
begin
FList.Delete(Index);
//---
FState := tsDelete;
FIndex := Index;
//---
self.NotifyEnabled := True;
end;
procedure TConcreteAggregate.Insert(Index: Integer; s: string);
begin
FList.Insert(Index, s);
//---
FState := tsInsert;
FIndex := Index;
//---
self.NotifyEnabled := True;
end;
end.
《GOF设计模式》—迭代器 (ITERATOR)—Delphi源码示例:健壮的迭代器
最新推荐文章于 2024-02-25 21:11:31 发布