示例:显式地指定感兴趣的改变 说明: 你可以扩展目标的注册接口,让各观察者注册为仅对特定事件感兴趣,以提高更新的效率。当一个事件发生时,目标仅通知那些已注册为对该事件感兴趣的观察者。 代码: unit uAspects; interface uses SysUtils, Classes, Dialogs; type TAspect = (apCalcEvent1,apCalcEvent2); TObserver = class; RMapInfo = record Interest:TAspect; Observer: TObserver; end; PMapInfo = ^RMapInfo; TMapList = class(TList) private function GetItems(Index: Integer): PMapInfo; protected procedure Notify(Ptr: Pointer; Action: TListNotification); override; public function Add(AInterest: TAspect; AObserver: TObserver): Integer; function IndexOf(AInterest: TAspect; AObserver: TObserver): Integer; procedure Delete(AInterest: TAspect; AObserver: TObserver); //--- property Items[Index: Integer]: PMapInfo read GetItems; end; TSubject = class private FObservers: TMapList; FInterest:TAspect; public constructor Create; destructor Destroy; override; //--- procedure Attach(AObserver: TObserver;AInterest:TAspect); procedure Detach(AObserver: TObserver;AInterest:TAspect); procedure Notify; end; TConcreteSubject = class(TSubject) private FState: Integer; public procedure Calc1; procedure Calc2; //--- property State: Integer read FState; end; TObserver = class public procedure Update(ASubject: TSubject;AInterest:TAspect); virtual; abstract; end; TConcreteObserver = class(TObserver) public procedure Update(ASubject: TSubject;AInterest:TAspect); override; end; procedure Test; implementation procedure Test; var ASubject: TConcreteSubject; AObserver: TObserver; begin ASubject := TConcreteSubject.Create; AObserver := TConcreteObserver.Create; try ASubject.Attach(AObserver,apCalcEvent2); ASubject.Calc1; ASubject.Calc2; finally AObserver.Free; ASubject.Free; end; end; constructor TSubject.Create; begin FObservers := TMapList.Create; end; destructor TSubject.Destroy; begin FObservers.Free; //--- inherited; end; procedure TSubject.Attach(AObserver: TObserver;AInterest:TAspect); begin FObservers.Add(AInterest,AObserver); end; procedure TSubject.Detach(AObserver: TObserver;AInterest:TAspect); begin FObservers.Delete(AInterest,AObserver); end; procedure TSubject.Notify; var i: integer; begin with FObservers do begin for i := 0 to Count - 1 do begin with Items[i]^ do begin if Interest = FInterest then Observer.Update(self,Interest); end; end; end; end; procedure TConcreteObserver.Update(ASubject: TSubject;AInterest:TAspect); begin if ASubject is TConcreteSubject then begin with TConcreteSubject(ASubject) do ShowMessage(IntToStr(State)); end; end; function TMapList.Add(AInterest: TAspect; AObserver: TObserver): Integer; var pData: PMapInfo; begin New(pData); pData.Interest := AInterest; pData.Observer := AObserver; //--- Result := inherited Add(pData); end; procedure TMapList.Delete(AInterest: TAspect; AObserver: TObserver); var AIndex:Integer; begin AIndex := IndexOf(AInterest, AObserver); if AIndex >= 0 then inherited Delete(AIndex); end; function TMapList.GetItems(Index: Integer): PMapInfo; begin Result := inherited Items[Index]; end; function TMapList.IndexOf(AInterest: TAspect; AObserver: TObserver): Integer; var i:Integer; begin for i := 0 to self.Count - 1 do begin with Self.Items[i]^ do if (Interest = AInterest) and (Observer = AObserver) then begin Result := i; Exit; end; end; //--- Result := -1; end; procedure TMapList.Notify(Ptr: Pointer; Action: TListNotification); begin if Action = lnDeleted then Dispose(Ptr); //--- inherited; end; procedure TConcreteSubject.Calc1; begin FInterest := apCalcEvent1; FState := FState + 1; //--- Self.Notify; end; procedure TConcreteSubject.Calc2; begin FInterest := apCalcEvent2; FState := FState * 2; //--- Self.Notify; end; end.