Sto cercando di creare un singleton in Delphi. L'ho fatto prima di utilizzare le versioni precedenti di Delphi e ho finito con l'utilizzo di variabili globali (nella sezione dell'implementazione) e l'utilizzo dell'inizializzazione e della finalizzazione per occuparmi dell'istanza. Inoltre non c'era modo di impedire all'utente di creare un'istanza in quanto non si poteva nascondere il costruttore standard. Mi chiedevo se una qualsiasi delle nuove funzionalità come i costruttori di classi e i distruttori e le variabili di classe (ok, non così nuove), forse i generici, potrebbero aiutare a creare una classe generica di singleton. Non sono ancora riuscito a creare qualcosa con mia soddisfazione.Creazione di un singleton in Delphi utilizzando le nuove funzionalità di D2009 e D2010
risposta
E 'stato possibile gestire questo sovrascrivendo l'allocatore e deallocatore metodi vero in Delphi, NewInstance e FreeInstance.Costruttori e distruttori in Delphi solo inizializzano e finalizzano rispettivamente, non allocano o deallocano la memoria, quindi tentare di nascondere i costruttori è sempre stato un po 'fuorviante.
cioè è stato possibile consentire l'uso gratuito di qualsiasi e tutti i costruttori il tempo che escludeva NewInstance tale che sempre e solo restituito un riferimento ad una sola dotazione di memoria per la classe.
Ma il tentativo di imporre un modello di utilizzo/comportamento in una classe base è un errore imho. Non tutti i modelli sono o richiedono classi specifiche per incapsulare il modello.
In casi come questo si finisce per creare qualcosa che è inutilmente complicato, e la complicazione attira errori nella mia esperienza e l'oggetto dell'esercizio quindi cerca di trovare difetti nell'implementazione del modello e poi cerca di implementare misure di salvaguardia contro quelli difetti, piuttosto che andare avanti con il lavoro pratico di lavoro che la classe singleton avrebbe dovuto svolgere.
È molto, molto più semplice e più efficace documentare l'uso della classe.
Documentazione come tecnica per l'attuazione di questo schema ha funzionato senza problemi per 15 anni per la Application e schermo oggetti nella VCL, ad esempio, per non parlare di innumerevoli altri single che ho creato in quegli anni.
Per un singleton, è possibile sovrascrivere il metodo NewInstance. E usa una variabile di classe. La variabile viene creata alla prima chiamata e restituisce il puntatore alla classe ogni altra chiamata.
Hai solo bisogno di trovare qualcosa per distruggerlo alla fine (probabilmente usando la finalizzazione).
In Delphi 2010 il modo migliore e più sicuro è utilizzare i costruttori di classe . Vedi here - leggi in particolare il paragrafo chiamato Incapsulamento migliorato.
HTH.
È un peccato che non si siano preoccupati di documentare correttamente questa funzione, o di includerla nelle "Novità" nella guida. – IanH
Preferisco utilizzare le interfacce quando ho bisogno di singleton e nascondere l'implementazione dell'interfaccia nella sezione di implementazione.
beneficia
- distruzione automatica quando il programma termina.
- Impossibile creare accidentalmente un TMySingleton.
svantaggi
- Qualcuno potrebbe decidere di attuare IMySingleton da solo.
Nota: Credo che l'uso di Singletons dovrebbe essere ridotto al minimo. Tutto sommato, i singleton sono poco più di variabili globali glorificate. Se e quando avvii l'unità testando il tuo codice, diventano un fastidio.
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.
+1 per la parte in corsivo su singleton. – mghie
@mghie: non sei d'accordo sull'implementazione del pattern? –
Sono d'accordo con te sul fatto che la maggior parte degli usi del modello Singleton non sono progressi rispetto alle variabili globali. Ma se uno vuole averli (per qualsiasi ragione), allora sarebbe necessaria una soluzione generica thread-safe. Il tuo non lo è, quindi potresti finire con più di un'istanza. Almeno non perde memoria, qualcosa che ho visto nelle grandi librerie commerciali dove gli oggetti vengono usati per l'implementazione di singleton invece delle interfacce. La soluzione di Moritz sembra essere thread-safe, ma dovrebbe essere controllata a fondo. – mghie
Se avete solo bisogno di un Singleton pianura, il modo più semplice è quello di utilizzare costruttori della classe e metodi di classe, come suggerito dal plainth. Ma i generici sono molto utili se hai bisogno di singleton con costruzione su richiesta (cioè al primo accesso).
Il seguente codice è preso da una delle mie unità di servizio; in pratica fornisce una generica fabbrica singleton per Delphi dal 2009 in poi.
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);
Uso come segue:
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;
Grande codice Moritz. –
Grazie. In effetti sarebbe più bello se potessi rimuovere i workarounds per D2009 :) –
Preferisco creare una classe singleton utilizzando un generatore di codice. Il problema con generico è che, tutto il codice viene generato in memoria, non nel file sorgente. Aumenterà la difficoltà del debugging.
C'è un modo per nascondere il costruttore "Crea" ereditato di TObject. Sebbene non sia possibile modificare il livello di accesso, può essere nascosto con un altro metodo senza parametri pubblico con lo stesso nome: "Crea". Questo semplifica enormemente l'implementazione della classe Singleton. Vedere la semplicità del codice:
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.
ho aggiunto i dettagli al mio post originale: http://www.yanniel.info/2010/10/singleton-pattern-delphi.html
- 1. Specificazione di nuove funzionalità
- 2. Creazione di un generico singleton
- 3. Nuove funzionalità di WPF 4?
- 4. Cercando di conoscere le nuove funzionalità asincroni in C#
- 5. Flex 4.10 nuove funzionalità
- 6. Polyfill o soluzioni alternative per le nuove funzionalità di ECMAScript5?
- 7. Funzionalità di callback tra Delphi DLL e Delphi EXE
- 8. Creazione istantanea di thread di un singleton
- 9. Quali sono le nuove funzionalità di Eclipse Helios?
- 10. I Generics in D2009 sono utilizzabili in progetti di grandi dimensioni?
- 11. Chiamare le attività di spegnimento in un singleton NancyFX Singleton
- 12. Creazione di un singleton con allocWithZone:
- 13. Esistono linee guida per la scrittura di API .NET utilizzando le nuove funzionalità async/await
- 14. elenco delle nuove funzionalità in C# 2.0, 3.0 e 4.0
- 15. Quali sono esattamente le nuove funzionalità ETW in CLR 4.0?
- 16. Quali saranno le nuove funzionalità disponibili in ASP.Net 4.0?
- 17. Creazione di nuove distribuzioni in scipy
- 18. Creazione di un riferimento statico contro un Singleton
- 19. Come disabilitare la creazione di nuove righe in un DataGridView?
- 20. Creazione di un elenco di selezione in stile che utilizza ancora le funzionalità di iOS
- 21. Come gestisci le nuove funzionalità di C# in modo che non conducano a codice scritto male?
- 22. Creazione di componenti UI accessibili in Delphi
- 23. Creazione di applicazioni Delphi multipiattaforma
- 24. Richiesto componente xml che supporta D2009
- 25. Dove posso trovare un elenco di funzionalità Android deprecate dalle nuove funzionalità?
- 26. Creazione di foglio di Excel da modello in Java, le nuove versioni di Excel
- 27. Creazione di una funzionalità di ricerca in ASP.NET
- 28. Compatibilità GWT con JDK 7 nuove funzionalità
- 29. Niente più unità xercesxmldom in Delphi XE?
- 30. Durata di un Singleton
o un distruttore di classe in D2010. –