示例:基于游标的迭代器 说明: 如果复合中的节点有一个接口可以从一个节点移到它的兄弟节点、父节点和子节点,那么基于游标的迭代器是个更好的选择。游标只需跟踪当前的节点;它可依赖这种节点接口来遍历该复合对象。 代码: unit uCompositeCursor; interface uses Dialogs, Contnrs; type TCursor = class; TComponent = class private FName: string; FParent: TComponent; protected function GetCount: integer; virtual; abstract; function GetItems(Index: integer): TComponent; virtual; abstract; function IndexOf(AItem: TComponent):Integer; virtual; abstract; //--- procedure First(ACursor: TCursor); procedure Next(ACursor: TCursor); function IsDone(ACursor: TCursor): Boolean; public constructor Create(AParent: TComponent;const AName: string); //--- function CreateCursor: TCursor; //--- property Name: string read FName; property Count: integer read GetCount; property Items[Index: integer]: TComponent read GetItems; default; property Parent: TComponent read FParent; end; TLeaf = class(TComponent) protected function GetCount: integer; override; function GetItems(Index: integer): TComponent; override; function IndexOf(AItem: TComponent): Integer; override; end; TComposite = class(TComponent) private FChilds: TObjectList; protected function GetCount: integer; override; function GetItems(Index: integer): TComponent; override; function IndexOf(AItem: TComponent): Integer; override; public constructor Create(AParent: TComponent;const AName: string); destructor Destroy; override; //--- procedure Add(AComponent: TComponent); end; TCursor = class private FComponent: TComponent; public constructor Create(const AComponent: TComponent); //--- procedure First(); procedure Next(); function IsDone(): Boolean; function CurrentItem: TComponent; end; procedure Test; implementation procedure Test; //--- procedure _ShowAggregate(I: TCursor); begin with I do begin First; while not IsDone do begin ShowMessage(CurrentItem.Name); Next; end; end; end; var AComposite, AComposite1: TComposite; ACursor: TCursor; begin AComposite := TComposite.Create(nil,'0'); try with AComposite do begin AComposite1 := TComposite.Create(AComposite,'1'); with AComposite1 do begin Add(TLeaf.Create(AComposite1,'11')); Add(TLeaf.Create(AComposite1,'12')); end; Add(AComposite1); //--- AComposite1 := TComposite.Create(AComposite,'2'); with AComposite1 do begin Add(TLeaf.Create(AComposite1,'21')); Add(TLeaf.Create(AComposite1,'22')); end; Add(AComposite1); //--- Add(TLeaf.Create(AComposite,'3')); Add(TLeaf.Create(AComposite,'4')); end; //--- ACursor := AComposite.CreateCursor; _ShowAggregate(ACursor); ACursor.Free; finally AComposite.Free; end; end; constructor TComposite.Create(AParent: TComponent;const AName: string); begin inherited; //--- FChilds := TObjectList.Create; end; destructor TComposite.Destroy; begin FChilds.Free; //--- inherited; end; procedure TComposite.Add(AComponent: TComponent); begin FChilds.Add(AComponent); end; function TComposite.GetItems(Index: integer): TComponent; begin Result := TComposite(FChilds[Index]); end; function TComposite.GetCount: integer; begin Result := FChilds.Count; end; function TComposite.IndexOf(AItem: TComponent): Integer; begin Result := FChilds.IndexOf(AItem); end; function TLeaf.GetCount: integer; begin Result := 0; end; function TLeaf.GetItems(Index: integer): TComponent; begin Result := nil; end; function TLeaf.IndexOf(AItem: TComponent): Integer; begin Result := -1; end; constructor TComponent.Create(AParent: TComponent;const AName: string); begin FParent := AParent; FName := AName; end; constructor TCursor.Create(const AComponent: TComponent); begin FComponent := AComponent; end; procedure TCursor.Next; begin FComponent.Next(self); end; function TCursor.IsDone: Boolean; begin Result := FComponent.IsDone(self); end; function TCursor.CurrentItem: TComponent; begin Result := FComponent; end; procedure TCursor.First; begin FComponent.First(self); end; function TComponent.CreateCursor: TCursor; begin Result := TCursor.Create(self); end; procedure TComponent.First(ACursor: TCursor); begin ACursor.FComponent := self; end; function TComponent.IsDone(ACursor: TCursor): Boolean; begin Result := (ACursor.FComponent = nil); end; procedure TComponent.Next(ACursor: TCursor); //--- function _Next(AParent,AItem:TComponent):TComponent; var AIndex:Integer; begin if AParent = nil then Result := nil else begin with AParent do begin AIndex := IndexOf(AItem); if (AIndex >= 0) and (AIndex < Count - 1) then Result := Items[AIndex + 1] else Result := _Next(AParent.Parent,AParent); end; end; end; begin if Self.Count > 0 then ACursor.FComponent := Self.Items[0] else if Self.Parent <> nil then ACursor.FComponent := _Next(Self.Parent,self) else ACursor.FComponent := nil; end; end.
