现在的DELPHI因为支持泛型的语法,所以也能支持模板编程了。
// 标准模板
unit UntPools;
interface
uses
Classes, SysUtils, UntThreadTimer;
type
{ 这是一个对像池, 可以池化所有 TObject 对像 }
{ 用法:
在一个全局的地方定义
var
Pooler: TObjectPool;
用到的地方
obj := Pooler.LockObject as Txxx;
try
finally
Pooler.UnlockObject;
end;
初始化
initialization
Pooler := TObjectPool.Create(要收集的类名)
finallization
Pooler.Free;
end;
}
//池中对象 状态
TPoolItem = class
private
FInstance: TObject; //对象
FLocked: Boolean; //是否被使用
FLastTime:TDateTime;//最近活跃时间
public
constructor Create(AInstance: TObject;const IsLocked :Boolean = True);
destructor Destroy; override;
end;
//对象池
TObjectPool = class
private
FCachedList: TThreadList;//对象池 中 对象 列表
FMaxCacheSize,FMinCacheSize: Integer; //对象池最大值,最小值 如不设置系统默认为 20
FCacheHit: Cardinal; //调用对象池 中 对象的 次数
FCreationCount: Cardinal; //创建对象次数
FObjectClass: TClass;
FRequestCount: Cardinal; //调用对象池次数
FAutoReleased: Boolean; //自动释放空闲的对象
FTimer:TThreadedTimer; //多线程计时器
FHourInterval:Integer; //设置间隔时间(小时)
function GetCurObjCount:Integer;
function GetLockObjCount:Integer;
procedure IniMinPools;//初始化最小池对象
procedure SetFHourInterval(iValue:Integer);
protected
function CreateObject: TObject;// 创建对象
procedure OnMyTimer(Sender: TObject);
public
constructor Create(AClass: TClass;MaxPools,MinPools:Integer);
destructor Destroy; override;
function LockObject: TObject;//获取对象
procedure UnlockObject(Instance: TObject); //释放对象
property ObjectClass: TClass read FObjectClass;
property MaxCacheSize: Integer read FMaxCacheSize;//池子大小
property CacheHit: Cardinal read FCacheHit; //调用池子中对象次数
property CreationCount: Cardinal read FCreationCount;//创建对象次数
property RequestCount: Cardinal read FRequestCount;//请求池次数
property RealCount : Integer read GetCurObjCount;//池中对象数量
property LockObjCount: Integer read GetLockObjCount;//池子繁忙的对象数量
property HourInterval: Integer read FHourInterval write SetFHourInterval;
procedure StartAutoFree; //开启自动回收
procedure StopAutoFree; //关闭自动回收
end;
{ TObjectPool<T> }
{ 同样是对像池, 但支持模板 }
{ 用法:
在一个全局的地方定义
var
Pooler: TObjectPool<要收集的类名>;
用到的地方
obj := Pooler.LockObject;
try
finally
Pooler.UnlockObject;
end;
初始化
initialization
Pooler := TObjectPool<要收集的类名>.Create;
finallization
Pooler.Free;
end;
}
TObjectPool<T: class> = class(TObjectPool)
public
constructor Create(const MaxPools:Integer = 0;const MinPools:Integer = 0);
function LockObject: T;
end;
implementation
{TPoolItem }
const
MSecsPerMins = SecsPerMin * MSecsPerSec;
//返回相差的分钟
function MyMinutesBetWeen(const ANow, AThen: TDateTime): Integer;
var
tmpDay:Double;
begin
tmpDay := 0;
if ANow < AThen then
tmpDay := AThen - ANow
else
tmpDay := ANow - AThen;
Result := Round(MinsPerDay * tmpDay);
end;
constructor TPoolItem.Create(AInstance: TObject;const IsLocked :Boolean);
begin
inherited Create;
FInstance := AInstance;
FLocked := IsLocked;
FLastTime := Now;
end;
destructor TPoolItem.Destroy;
begin
if Assigned(FInstance) then FreeAndNil(FInstance);
inherited;
end;
{ TObjectPool }
constructor TObjectPool.Create(AClass: TClass; MaxPools, MinPools: Integer);
begin
inherited Create;
FObjectClass := AClass;
FCachedList := TThreadList.Create;
FMaxCacheSize := MaxPools;
FMinCacheSize := MinPools;
if FMaxCacheSize = 0 then FMaxCacheSize := 20; //系统默认为20个并发
if FMinCacheSize > FMaxCacheSize then FMinCacheSize := FMaxCacheSize;//系统默认最小值为0
FCacheHit := 0;
FCreationCount := 0;
FRequestCount := 0;
IniMinPools; //初始化最小池对象
//计时销毁
FTimer := TThreadedTimer.Create(nil); //计时
FHourInterval := 4; //默认空闲4小时则回收
FTimer.Interval := MSecsPerMins * MinsPerHour * FHourInterval;
FTimer.OnTimer := OnMyTimer;
end;
function TObjectPool.CreateObject: TObject;
begin
Result := FObjectClass.NewInstance;
if Result is TDataModule then
TDataModule(Result).Create(nil)
else if Result is TComponent then
TComponent(Result).Create(nil)
else if Result is TPersistent then
TPersistent(Result).Create
else Result.Create;
end;
destructor TObjectPool.Destroy;
var
I: Integer;
LockedList: TList;
begin
if Assigned(FCachedList) then
begin
LockedList := FCachedList.LockList;
try
for I := 0 to LockedList.Count - 1 do
TPoolItem(LockedList[I]).Free;
finally
FCachedList.UnlockList;
FCachedList.Free;
end;
end;
FTimer.Free;
inherited;
end;
function TObjectPool.GetCurObjCount: Integer;
var
LockedList: TList;
begin
Result := 0;
LockedList := FCachedList.LockList;
try
Result := LockedList.Count;
finally
FCachedList.UnlockList;
end;
end;
function TObjectPool.GetLockObjCount: Integer;
var
LockedList: TList;
i:Integer;
begin
Result := 0;
LockedList := FCachedList.LockList;
try
for I := 0 to LockedList.Count - 1 do
begin
if TPoolItem(LockedList[I]).FLocked then Result := Result + 1;
end;
finally
FCachedList.UnlockList;
end;
end;
procedure TObjectPool.IniMinPools;
var
PoolsObject: TObject;
LockedList: TList;
I: Integer;
begin
LockedList := FCachedList.LockList;
try
for I := 0 to FMinCacheSize - 1 do
begin
PoolsObject := CreateObject;
if Assigned(PoolsObject) then
LockedList.Add(TPoolItem.Create(PoolsObject,False));
end;
finally
FCachedList.UnlockList;
end;
end;
function TObjectPool.LockObject: TObject;
var
LockedList: TList;
I: Integer;
begin
Result := nil;
LockedList := FCachedList.LockList;
try
Inc(FRequestCount);
for i := 0 to LockedList.Count - 1 do
begin
if not TPoolItem(LockedList.Items[i]).FLocked then
begin
Result := TPoolItem(LockedList.Items[i]).FInstance;
TPoolItem(LockedList.Items[i]).FLocked := True;
TPoolItem(LockedList.Items[i]).FLastTime := Now;
Inc(FCacheHit);//从池中取的次数
Break;
end;
end;
//
if not Assigned(Result) then
begin
Result := CreateObject;
//Assert(Assigned(Result));
Inc(FCreationCount);
if LockedList.Count < FMaxCacheSize then //池子容量
LockedList.Add(TPoolItem.Create(Result,True));
end;
finally
FCachedList.UnlockList;
end;
end;
procedure TObjectPool.OnMyTimer(Sender: TObject);
var
i:Integer;
LockedList: TList;
begin
LockedList := FCachedList.LockList;
try
for I := LockedList.Count - 1 downto 0 do
begin
if MyMinutesBetween(Now,TPoolItem(LockedList.Items[i]).FLastTime) >= FHourInterval * MinsPerHour then //释放池子许久不用的ADO
begin
TPoolItem(LockedList.Items[i]).Free;
LockedList.Delete(I);
end;
end;
finally
FCachedList.UnlockList;
end;
end;
procedure TObjectPool.SetFHourInterval(iValue: Integer);
begin
if iValue <= 1 then Exit;
if FHourInterval = iValue then Exit;
FTimer.Enabled := False;
try
FHourInterval := iValue;
FTimer.Interval := MSecsPerMins * MinsPerHour * FHourInterval;
finally
FTimer.Enabled := True;
end;
end;
procedure TObjectPool.StartAutoFree;
begin
if not FTimer.Enabled then FTimer.Enabled := True;
end;
procedure TObjectPool.StopAutoFree;
begin
if FTimer.Enabled then FTimer.Enabled := False;
end;
procedure TObjectPool.UnlockObject(Instance: TObject);
var
LockedList: TList;
I: Integer;
Item: TPoolItem;
begin
LockedList := FCachedList.LockList;
try
Item := nil;
for i := 0 to LockedList.Count - 1 do
begin
Item := TPoolItem(LockedList.Items[i]);
if Item.FInstance = Instance then
begin
Item.FLocked := False;
Item.FLastTime := Now;
Break;
end;
end;
if not Assigned(Item) then Instance.Free;
finally
FCachedList.UnlockList;
end;
end;
// 基于标准模板定义的泛型模板
{ TObjectPool<T> }
constructor TObjectPool<T>.Create(const MaxPools, MinPools: Integer);
begin
inherited Create(T,MaxPools,MinPools);
end;
function TObjectPool<T>.LockObject: T;
begin
Result := T(inherited LockObject);
end;
end.
// 基于泛型模板定义的具体模板
var
FQueryMgr:TObjectPool<TUniQuery>; //Query池子
FDspMgr:TObjectPool<TDataSetProvider>;//DSP池子
FCDSMgr:TObjectPool<TClientDataSet>;//cds池子
FDSMgr :TObjectPool<TDataSource>;//ds池子
FUniSQLMgr:TObjectPool<TUniSQL>;//执行SQL池子
FUniSPMgr :TObjectPool<TUniStoredProc>;//存储过程池子
// 创建具体模板
function QueryMgr:TObjectPool<TUniQuery>;
begin
if not Assigned(FQueryMgr) then
FQueryMgr := TObjectPool<TUniQuery>.Create(1000,20);
Result := FQueryMgr;
end;