简单的Delphi对象管理器
《掺和比试》时得到的一个副产品。
原 理很简单,就是创建的对象放到一个池里,暂时不释放,再分配的时候可以重用。对于需要反复大量创建删除同一个类的对象时,或是创建对象成本很高的情况下, 这个东东有一定的作用。另外还弄了一个通用的对象管理,不提供POOL的缓冲,仅提供自动释放,纯粹是为了方便,这个可以不针对特定对象。
使用方法:
uses objmngr; ... Type TDummy = Class(.... Constructor Create(...); Function Init(...) : TDummy; ... End; ... Var DummyPool : TMObjPool; ... Function TDummy.Init(...) : TDummy; Begin ... Result := Self; End; ... // Pool Var om : IMObjPoolManager; Begin om := TMObjPoolManager.Create(DummyPool, 50); d1 := (om.New As TDummy).Init(...); // Create new dummy object ... End; // om and all new dummy objects will be released automatically ... // Nopool Var om : IMObjManager; Begin om := TMObjManager.Create(50); d1 := om.New(TDummy.Create(...)) As TDummy; d2 := om.New(TOther.Create(...)) As TOther; ... End; // om and all managed objects will be release automatically ... Initialization DummyPool := TMObjPool.Create(TDummy, 5000); ... Finallization DummyPool.Free;
注意:因为自动创建对象时无法确定构造函数参数,所以只能调用无参数的构造函数,如需初始化对象,则需要再定义一个Init函数供调用。因为Init函数取代了构造函数的功能,所以还需要它返回Self给调用者。
管理单元objmngr.pas源码:
unit objmngr;{$IFDEF FPC}{$mode objfpc}{$H+}{$ENDIF}
interface
uses Classes, SysUtils;
Type
TMBucket = Record Key : TObject; Value : TObject; end;
PMBucket = ^TMBucket;
TMHashMap = Class(TObject) Private FSize : Integer; FItems : Array Of TMBucket; Protected Function HashFunc(Key : TObject) : Integer; Function FindKey(Key : TObject) : Integer; Function FindEmpty(Key : TObject) : Integer; Function GetItem(Key : TObject) : TObject; Public Constructor Create(ASize : Integer); Destructor Destroy; Override;
Procedure AddItem(Key, Value : TObject); Procedure DelItem(Key : TObject); Function PopItem(Key : TObject) : TObject; Property Items[Key : TObject] : TObject Read GetItem;
End;
TMStack = Class(TObject) Private FData : Array Of TObject; FTop : Integer; Public Constructor Create(ASize : Integer); Destructor Destroy; Override; Procedure Push(AObj : TObject); Function Pop : TObject; Function IsEmpty : Boolean; End;
TMObjPool = Class(TObject) Private FMeta : TClass; FPool : Array Of TObject; FIndex : Integer; FMap : TMHashMap; FFree : TMStack; Public Constructor Create(AMeta : TClass; ASize : Integer); Destructor Destroy; Override;
Function NewObj : TObject; Procedure FreeObj(AObj : TObject);
End;
IMObjPoolManager = Interface Function New : TObject; End;
TMObjPoolManager = Class(TInterfacedObject, IMObjPoolManager) Private FPool : TMObjPool; FObjs : TMStack; Public Function New : TObject; Overload;
Constructor Create(APool : TMObjPool; ASize : Integer = 1000); Destructor Destroy; Override; End;
IMObjManager = Interface Function New(AObj : TObject) : TObject; End;
TMObjManager = Class(TInterfacedObject, IMObjManager) Private FObjs : TMStack; Public Function New(AObj : TObject) : TObject; Overload;
Constructor Create(ASize : Integer = 1000); Destructor Destroy; Override; End;
implementation
{ TMHashMap }
Constructor TMHashMap.Create(ASize : Integer); Begin FSize := ASize; SetLength(FItems, FSize); FillChar(FItems[0], FSize * SizeOf(TMBucket), 0); End;
Destructor TMHashMap.Destroy; Begin SetLength(FItems, 0); Inherited; End;
Function TMHashMap.HashFunc(Key : TObject) : Integer; Begin Result := Integer(Key) Mod FSize; End;
Function TMHashMap.FindKey(Key : TObject) : Integer; Var i, n : Integer; Begin n := HashFunc(Key); Result := -1; If FItems[n].Key = Key Then Result := n Else Begin i := n; Repeat i := (i + 1) Mod FSize; If FItems[i].Key = Key Then Begin Result := i; Break; End; Until i = n; End; End;
Function TMHashMap.FindEmpty(Key : TObject) : Integer; Var i, n : Integer; Begin n := HashFunc(Key); If Integer(FItems[n].Key) = 0 Then Result := n Else Begin i := n; Repeat i := (i + 1) Mod FSize; If Integer(FItems[i].Key) = 0 Then Begin Result := i; Exit; End; Until i = n; Raise Exception.Create('Map is full!'); End; End;
Function TMHashMap.GetItem(Key : TObject) : TObject; Var i : Integer; Begin i := FindKey(Key); If i >= 0 Then Result := FItems[i].Value Else Result := Nil; End;
Procedure TMHashMap.AddItem(Key, Value : TObject); Var i : Integer; Begin i := FindEmpty(Key); FItems[i].Key := Key; FItems[i].Value := Value; End;
Procedure TMHashMap.DelItem(Key : TObject); Var i : Integer; Begin i := FindKey(Key); If i >= 0 Then Begin FItems[i].Key := TObject(0); FItems[i].Value := Nil; End; End;
Function TMHashMap.PopItem(Key : TObject) : TObject; Var i : Integer; Begin i := FindKey(Key); If i >= 0 Then Begin Result := FItems[i].Value; FItems[i].Key := TObject(0); FItems[i].Value := Nil; End Else Result := Nil; End;
{ TMStack }
Constructor TMStack.Create(ASize : Integer); Begin SetLength(FData, ASize); FTop := 0; end;
Destructor TMStack.Destroy; Begin SetLength(FData, 0); Inherited; end;
Procedure TMStack.Push(AObj : TObject); Begin FData[FTop] := AObj; Inc(FTop); If FTop >= Length(FData) Then Raise Exception.Create('Queue is full!'); end;
Function TMStack.Pop : TObject; Begin If FTop = 0 Then Raise Exception.Create('Queue is empty!'); Dec(FTop); Result := FData[FTop]; end;
Function TMStack.IsEmpty : Boolean; Begin Result := (FTop = 0); end;
{ TMObjPool }
Constructor TMObjPool.Create(AMeta : TClass; ASize : Integer); Begin FMeta := AMeta; SetLength(FPool, ASize); FIndex := 0; FMap := TMHashMap.Create(ASize * 4); FFree := TMStack.Create(ASize); End;
Destructor TMObjPool.Destroy; Var i : Integer; Begin FFree.Free; FMap.Free; For i := 0 To FIndex - 1 Do FPool[i].Free; Inherited; End;
Function TMObjPool.NewObj : TObject; Var i : Integer; Begin If FFree.IsEmpty Then Begin Result := FMeta.Create; FPool[FIndex] := Result; i := FIndex; Inc(FIndex); End Else Begin i := Integer(FFree.Pop); Result := FPool[i]; End; FMap.AddItem(Result, TObject(i)); End;
Procedure TMObjPool.FreeObj(AObj : TObject); Var i : Integer; Begin i := Integer(FMap.PopItem(AObj)); FFree.Push(TObject(i)); End;
{ TMObjPoolManager }
Constructor TMObjPoolManager.Create(APool : TMObjPool; ASize : Integer); Begin FPool := APool; FObjs := TMStack.Create(ASize); End;
Destructor TMObjPoolManager.Destroy; Begin While Not FObjs.IsEmpty Do FPool.FreeObj(FObjs.Pop); FObjs.Free; Inherited; end;
Function TMObjPoolManager.New : TObject; Begin Result := FPool.NewObj; FObjs.Push(Result); end;
{ TMObjManager }
constructor TMObjManager.Create(ASize: Integer); begin FObjs := TMStack.Create(ASize); end;
destructor TMObjManager.Destroy; begin While Not FObjs.IsEmpty Do FObjs.Pop.Free; FObjs.Free; Inherited; end;
function TMObjManager.New(AObj: TObject): TObject; begin FObjs.Push(AObj); Result := AObj; end;
end.
草草写就,应该还有优化的余地。
推送到[go4pro.org]