我正在尋找在Delphi中創建單例。在使用舊版本的Delphi之前,我已經完成了這個工作,最後使用了全局變量(在實現部分),並使用初始化和終結來處理實例。也無法阻止用戶創建實例,因爲您無法隱藏標準構造函數。我想知道是否有任何新的功能,如類構造函數和析構函數,以及類變量(好,不是那麼新),也許泛型,可以幫助創建一個通用的單例類。我還沒有設法讓我滿意。使用D2009和D2010的新功能在Delphi中創建單例
回答
有可能通過覆蓋在Delphi中TRUE分配器和釋放器的方法,NewInstance方法和FreeInstance來管理這一點。Delphi中的構造函數和析構函數只分別初始化和終止,它們不分配或解除分配內存,所以試圖隱藏構造函數總是有點誤導。
即有可能允許自由使用的任何和所有構造函數,只要你推翻NewInstance方法,使得它永遠只能返回的類的內存單一分配的參考。
但是試圖在基類中強制使用/行爲模式是一個錯誤。並非所有模式都是或需要特定類來封裝模式。
在這種情況下,您最終會創建一些不必要的複雜內容,並且複雜性會吸引我的經驗和練習對象中的錯誤,然後嘗試在模式實現中發現缺陷,然後嘗試實施針對這些模式的保護措施缺點,而不是完成單身人士課程應該完成的實際工作。
遠遠更遠,更簡單,更有效地記錄類的用法。
文檔作爲實現這種模式的技術已經完美地工作了15年的應用和屏幕在VCL對象,例如,何況我在那些年裏創造了無數的其他單身。
對於單身人士,您可以重寫NewInstance方法。並使用類變量。您在第一次調用時創建變量並將指針返回給彼此呼叫的類。
你只需要找到一些最終銷燬它(可能使用finalize)。
我更喜歡在需要單例時使用接口,並在實現部分隱藏接口的實現。
利於
- 自動銷燬的程序終止時。
- 沒辦法意外地創建一個TMySingleton。
弊端
- 有人可能決定實現自身IMySingleton。
注意:我相信單身人士的使用應該保持在絕對最低限度。總而言之,單身人士不僅僅是榮耀的全球變數。如果並且當你開始單元測試你的代碼時,它們會變成討厭的東西。
unit uSingleton;
interface
type
ISingleton = interface
['{8A449E4B-DEF9-400E-9C21-93DFA2D5F662}']
end;
function Singleton: ISingleton;
implementation
uses
SyncObjs;
type
TSingleton = class(TInterfacedObject, ISingleton);
var
Lock: TCriticalSection;
function Singleton: ISingleton;
const
_singleton: ISingleton = nil;
begin
if not Assigned(_singleton) then
begin
Lock.Acquire;
try
if not Assigned(_singleton) then
_singleton := TSingleton.Create();
finally
Lock.Release;
end;
end;
Result := _singleton;
end;
initialization
Lock := TCriticalSection.Create;
finalization
Lock.Free;
end.
如果你只需要一個簡單的單,最簡單的方法是使用類構造函數和類方法通過plainth的建議。但是,如果您需要按需構建單例(即第一次訪問),泛型非常有用。
以下代碼來自我的一個公用事業單位;它基本上爲德爾福2009年以後提供了一個通用的單體工廠。
interface
type
{$HINTS OFF}
{ TSingletonInstance<> implements lazy creation, which is sometimes useful for avoiding
expensive initialization operations.
If you do not require lazy creation and you target only Delphi 2010 onwards, you should
use class constructors and class destructors instead to implement singletons. }
TSingletonInstance<T: class, constructor> = record
private
FGuard: IInterface;
FInstance: T;
function GetInstance: T;
function CreateInstance: TObject;
public
property Instance: T read GetInstance;
end;
{$HINTS ON}
TSingletonFactoryFunction = function: TObject of object;
{ Private symbols (which are in the interface section because of known limitations of generics) }
procedure _AllocateSingletonInstance (InstanceRecord: Pointer; Factory: TSingletonFactoryFunction);
implementation
{ TSingleton }
var
SingletonCriticalSection: TRTLCriticalSection;
type
TSingletonGuard = class (TInterfacedObject)
private
FSingletonInstance: TObject;
public
constructor Create (AInstance: TObject);
destructor Destroy; override;
end;
PUntypedSingletonInstance = ^TUntypedSingletonInstance;
TUntypedSingletonInstance = record
FGuard: IInterface;
FInstance: TObject;
end;
// TODO: is a lock required for multiple threads accessing a single interface variable?
procedure _AllocateSingletonInstance (InstanceRecord: Pointer; Factory: TSingletonFactoryFunction);
var
USI: PUntypedSingletonInstance;
begin
USI := PUntypedSingletonInstance (InstanceRecord);
EnterCriticalSection (SingletonCriticalSection);
if USI.FInstance = nil then
begin
USI.FInstance := Factory();
USI.FGuard := TSingletonGuard.Create (USI.FInstance);
end;
LeaveCriticalSection (SingletonCriticalSection);
end;
constructor TSingletonGuard.Create (AInstance: TObject);
begin
FSingletonInstance := AInstance;
end;
destructor TSingletonGuard.Destroy;
begin
FSingletonInstance.Free;
inherited;
end;
function TSingletonInstance<T>.GetInstance: T;
var
Factory: TSingletonFactoryFunction;
begin
if FInstance = nil then
begin
Factory := Self.CreateInstance; // TODO: associate QC report
_AllocateSingletonInstance (@Self, Factory);
end;
Result := FInstance;
end;
function TSingletonInstance<T>.CreateInstance: TObject;
begin
Result := T.Create;
end;
initialization
InitializeCriticalSection (SingletonCriticalSection);
finalization
DeleteCriticalSection (SingletonCriticalSection);
用法如下:
type
TMySingleton = class
public
constructor Create;
class function Get: TMySingleton; static;
end;
var
MySingletonInstance: TSingletonInstance<TMySingleton>;
class function TMySingleton.Get: TMySingleton;
begin
Result := MySingletonInstance.Instance;
end;
偉大的代碼莫里茨。 –
謝謝。事實上,如果我可以刪除D2009的解決方法,它會更漂亮:) –
我更喜歡使用代碼生成器創建單例類。泛型的問題在於,所有代碼都是在內存中生成的,而不是在源文件中生成的。這會增加調試的難度。
有一種方法可以隱藏TObject的繼承的「創建」構造函數。儘管無法更改訪問級別,但可以使用另一個具有相同名稱的公共無參數方法隱藏:「創建」。這極大地簡化了Singleton類的實現。看到代碼的簡單:
unit Singleton;
interface
type
TSingleton = class
private
class var _instance: TSingleton;
public
//Global point of access to the unique instance
class function Create: TSingleton;
destructor Destroy; override;
end;
implementation
{ TSingleton }
class function TSingleton.Create: TSingleton;
begin
if (_instance = nil) then
_instance:= inherited Create as Self;
result:= _instance;
end;
destructor TSingleton.Destroy;
begin
_instance:= nil;
inherited;
end;
end.
我添加了細節,我原來的職位:http://www.yanniel.info/2010/10/singleton-pattern-delphi.html
- 1. Delphi D2009 for Win32和CodeDom
- 2. 創建功能使單例類PHP
- 3. 德爾福,如何避免D2009 unicode的警告信息,D2010
- 4. Orangehrm:創建新的菜單功能
- 5. 在Delphi中使用Delphi創建表格和自動增加列
- 6. 重新創建損壞的Delphi表單
- 7. 創建和使用用戶功能lesscss
- 8. 更新在Firebase中創建的集合(使用雲功能)
- 9. 使用Timesteps和多個功能創建一個新陣列,例如對於LSTM
- 10. delphi表單創建
- 11. 使用phpMyAdmin創建功能
- 12. 何時創建新功能?
- 13. 創建表單功能Html
- 14. 在Delphi中創建表單編輯器
- 15. 在delphi中創建表單時出錯
- 16. 使用GDAL和Delphi創建等高線
- 17. 錯誤使用C創建新的存儲功能,在BIGINT
- 18. 創建在Delphi使用的GetTickCount
- 19. 在TabControl中剪切和粘貼控件創建了新功能
- 20. 在iOS中創建登錄功能和搜索功能
- 21. 在delphi SDI中創建新表單時傳遞參數
- 22. 如何創建「新」功能,採用Delphi XSD數據綁定向導
- 23. 在wxpython中使用wx.TextCtrl和按鈕單擊後顯示數據的簡單示例 - wx中的新功能
- 24. 在Delphi中創建和加載資源
- 25. 如何在Cocoa應用程序的菜單欄中創建「新窗口」功能?
- 26. android.app.Application單例實例被重新創建
- 27. 的ClassInfo功能在Delphi 7
- 28. 我使用Delphi中的鉻,但我覺得我不能創建
- 29. 創建和使用功能的註冊表在F#
- 30. 使創建和只讀表單中的功能區按鈕不可用
或D2010類的析構函數。 –