《GOF设计模式》—迭代器 (ITERATOR)—Delphi源码示例:健壮的迭代器

    技术2026-05-13  0

    示例:健壮的迭代器 说明: 一个健壮的迭代器(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.

    最新回复(0)