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

示例:健壮的迭代器
说明:
一个健壮的迭代器(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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值