设计模式、用Delphi描述-->Lock pattern

    技术2022-05-11  113

     

    Lock pattern

    起源

    lock patternDelphi TStrings数据更新控制的基础。在本段后面将例举部分TstringsTstringList的代码

    目的

    为类提供一个临时的访问锁控制机制

    动机

    我们经常发现一个对象经常调度一个返回更改结果的通知。被调度的对象必须控制其内部状态,以同步对象数据。如果同时对一个对象进行多个更改操作,将会产生多个通知并产生一个并发的操作。此时在你的类中加入一个lock pattern的模式,从面提供一个临时锁控制机。从而避免不必要的通知。

    我们通过Tbag类来学习:

    TBag提供了collection的行为。每次更改Tbag将调度OnChange事件。如果我们一次对Tbag加入多个对象你将得到多个更改通知。一个图形组件可能会进行多次刷新操作。引入lock pattern在加入对象前打开Tbag的锁,操作完后关闭锁。如此,我将得到单一的更改通知。更好的办法是加入一个标志,比如:FUpdating

    应用

    以下是Tbag类部分代码: (仅显示部分相关代码)

     

    type

      TBag = class (TObject)

      private

        FLockCnt: Integer;

      protected

        function Locked: Boolean;

        procedure SetLocking(Updating: Boolean);

      public

        procedure Lock;

        procedure UnLock;

      end;

     

    implementation

     

    procedure TBag.Lock;

    begin

      Inc(FLockCnt);

      if FLockCnt = 1 then SetLocking(False);

    end;

     

    function TBag.Locked: Boolean;

    begin

      Result := (FLockCnt <> 0);

    end;

     

    procedure TBag.SetLocking(Updating: Boolean);

    begin

    end;

     

    procedure TBag.UnLock;

    begin

      Dec(FLockCnt);

      if FLockCnt = 0 then SetLocking(True);

    end;

     

    Tbag说明:

    ·      FlockCnt保存锁机制的内部状态。FLockCnt = 0表示其处于非锁状态,其它值都表示其处于锁定状态。类Tbag通过LockUnlock来设置它的值。

    ·      LockUnlock提供了锁的接口,每一次调用都将引起锁的关态变化,并调用SetLocking方法。

    ·      SetLocking方法中有一个Updating的参数,Lock调用的参数为False,而Unlock调用的参数为True。对了,你可以在方法中插入一引起其它的代码,分配给它更多的操作表示它的锁状态的更改。.

    ·      Locked 返回类的锁状态。

    注意:Lock Unlock必须同时使用,从而避免类保持在锁状态。明智的方法是使用try..finally块来保持Lock Unlock的同时调用。

     

    一个典型的应用例子:

     

    procedure TBag.Add(Item: Pointer);

    begin

      { Add Item to internal structure }

      Change;

    end

     

    procedure TBag.AddItems(Items: TList);

    begin

      Lock;

      { Add multiple items }

      try

        for I := 0 to Items.Count - 1 do

          Add(Items[I]);

      finally

        { use try..finally to make sure Unlock is called }

        Unlock;

      end;

    end;

     

    procedure TBag.Change;

    begin

      if not Locked then

        if Assigned(FOnChange) then FOnChange(Self);

    end;

     

    procedure TBag.SetLocking(Updating: Boolean);

    begin

      if Updating then { Bag has become unlocked }

        Change;

    end;

    Delphi实例:TStringTstringList

    TStrings = class(TPersistent)

      private

    FUpdateCount: Integer;

      Protected

    procedure Exchange(Index1, Index2: Integer); virtual;

    procedure SetUpdateState(Updating: Boolean); virtual;

    public

      procedure BeginUpdate;

      procedure EndUpdate;

    procedure Changed; virtual;

           procedure Changing; virtual;


    最新回复(0)