Deux méthodes d'implémentation du mode Singleton dans Delphi
haozi
Résumé Cet article décrit deux implémentations Delphi du mode Singleton et fait une analyse comparative.
Modèle de conception de mots clés, Singleton
Le modèle Singleton est un modèle de conception très utile. Son intention est simplement de créer une instance d’une classe et de lui fournir un point d’accès global. Les variables globales rendent un objet facilement accessible, mais ne vous empêchent pas d'instancier plusieurs objets. Le but du modèle singleton est de garantir qu’une seule instance existe pendant le cycle de vie du programme.
Regardez le code ci-dessous :
PRécédure TForm1.Button1Click(Expéditeur : TObject);
var lS1 : TSingleton l;
S2 : TSingleton ;
commencer
try lS1 := TSingleton.Create; ////Appelle le constructeur de la classe
lS2 := TSingleton.Create; ////Appelle le constructeur de la classe
//// ...autre code
enfin
lS1.Free; ////Libérer l'objet
lS2.Free; ////Libérer l'objet
fin;
fin;
Dans le code ci-dessus, la classe TSingleton est instanciée lorsque la fonction Create est appelée pour la première fois, lS1 pointe vers l'adresse d'un objet de stockage mémoire. Lorsque la fonction TSingleton.Create est appelée pour la deuxième fois, l'objet TSingleton est réinitialisé. -instancié. lS2 pointe vers l'adresse mémoire allouée. Le modèle Singleton consiste à laisser la classe elle-même se charger de la sauvegarde de sa seule instance.
Dans le code ci-dessus, lorsque ls2 est créé, il pointe également vers l'objet pointé par ls1 (c'est-à-dire qu'il se voit attribuer la même adresse mémoire. De même, nous devons empêcher la libération de la mémoire lors de la libération de ls1, car le seul). L'objet est également référencé par ls2. Cela garantit qu'il n'y a qu'une seule instance de classe pendant le cycle de vie du programme.
L'exemple de code C++ dans « Design Pattern » utilise des variables membres statiques C++ pour enregistrer les instances et utilise des fonctions de constructeur protégées. Cependant, comme il n’existe pas de variables membres statiques dans Delphi, la méthode de cet exemple en mode singleton ne peut pas être utilisée telle quelle. Ci-dessous, nous analysons plusieurs façons permettant à DELPHI d'implémenter le mode Singleton.
un. Méthode basée sur le remplacement de deux fonctions virtuelles Tobject
fonction de classe NewInstance : TObject virtuel ;
procédure FreeInstance ; virtuelle ;
La fonction NewInstance se charge d'allouer de la mémoire à l'objet lors de la création de l'objet de classe, tandis que FreeInstance libère la mémoire au contraire.
.
Le premier est appelé lorsque l’objet est construit et le second lorsque l’objet est détruit.
Nous utilisons deux variables globales pour contenir l'objet singleton et le nombre de références de l'objet.
varInstance : TSingleton = nul ;
RefCount : Entier = 0 ;
Unités de la classe TSingleton :
////------------------------------------------------------------ -- --------------------------
////
unité uSingleton ;
interface
taper
TSingleton = classe (TObject)
publique
fonction de classe NewInstance : TObject ; remplacement ; ////Remplacer la fonction de classe de base
procédure FreeInstance ; remplacement ; ////Remplacer la fonction de classe de base
fonction de classe RefCount : Integer ;////Renvoie le décompte de référence actuel
fin;
//// Déclaration des variables globales
var
Instance : TSingleton = nul ;
RefCount : entier = 0 ;
mise en œuvre
{TSingleton}
procédure TSingleton.FreeInstance ;
commencer
Dec( RefCount );////Diminuer le nombre de références
if (RefCount = 0) then////Est-ce 0, si c'est le cas, libérez la mémoire
commencer
Instance := nulle ;
//// Libère les variables privées de la classe singleton
////…
FreeInstance héritée ;
fin;
fin;
fonction de classe TSingleton.NewInstance : TObject ;
commencer
if (non assigné (instance)) alors
commencer
Instance := TSingleton (NewInstance héritée);
////Exemple d'initialisation de variables privées :
//// Instance.VariableName := Valeur ;
fin;
Résultat := Instance ;
Inc( RefCount );
fin;
fonction de classe TSingleton.RefCount : entier ;
commencer
Résultat := RefCount ;
fin;
fin.
////------------------------------------------------------------ -- --------------------------
////
Lorsque le constructeur de TSingleton est appelé, notre fonction de remplacement NewInstance sera appelée, et NewInstance allouera de la mémoire et la renverra au constructeur. De cette façon, via la fonction de remplacement NewInstance, nous garantissons que la fonction Create ne peut instancier qu'un objet TSingleton. (quel que soit le nombre d'appels) Create renvoie uniquement l'adresse mémoire allouée pour la première fois). En même temps, la variable RefCount contient le nombre de références dont nous disposons à l'objet.
Regardons le code du test
procédure TForm1.Button1Click(Expéditeur : TObject);
var
lS1, lS2 : TSingleton ;
Ob1, Ob2 : Tobjet ;
commencer
lS1 := TSingleton.Create;
ShowMessage (IntToStr (RefCount)); //// Ref_Count = 1
lS2 := TSingleton.Create;
ShowMessage (IntToStr (RefCount)); //// Ref_Count = 2
Ob1 := TObject.Create;
Ob2 := Tobject.Create;
si lS1 = lS2 alors
ShowMessage('Les adresses sont égales') //// lS1 = lS2
autre
ShowMessage('Les adresses ne sont pas égales');
si Ob1 = Ob2 alors
ShowMessage('Les adresses sont égales')
autre
ShowMessage('Les adresses ne sont pas égales'); //// Ob1 <> Ob2
fin;
Lorsque le programme appelle le destructeur (c'est-à-dire lorsque la fonction FREE est appelée), le destructeur appellera la fonction FreeInstance pour libérer la mémoire allouée par le constructeur. La fonction FreeInstance de Override garantit que la mémoire de l'objet en mode singleton est libérée uniquement lorsque le nombre de références atteint zéro.
Voici notre code de test :
var
lS1 : TSingleton ;
lS2 : TSingleton ;
commencer
essayer
lS1 := TSingleton.Create; ////Appelle le constructeur de la classe
lS2 := TSingleton.Create; ////Appelle le constructeur de la classe
//// ...autre code
enfin
lS1.Free; ////Ici, nous appellerons d'abord la FreeInstance définie par notre override,
////Puisque RefCount est 1 après avoir décrémenté 1 à ce moment, l'objet singleton n'a pas été libéré.
lS2.Free; ////dec(RefCount)= 0 libère l'objet singleton
fin;
fin;
La méthode d'implémentation de modèle singleton ci-dessus est un bon moyen de réaliser que la classe elle-même est responsable de la sauvegarde de sa propre instance unique (en interceptant la demande de création d'un nouvel objet - reportez-vous aux "Modèles de conception". Elle n'a aucune restriction particulière sur l'utilisation de la classe TSingleton - —Les programmeurs peuvent appeler les fonctions Create et Free à volonté.
L'inconvénient de ce mode est que la classe TSingleton ne peut pas être héritée en tant que classe parent pour générer des sous-classes. Si l'héritage génère deux sous-classes, un seul objet sera généré lors de la création.
procédure TForm1.Button1Click(Expéditeur : TObject);
var
lS1 : sous-catégorie un ;
lS2 : sous-catégorie deux ;
commencer
lS1 := Sous-classe 1.Create;
lS2 := Sous-classe 2.Create; ////La sous-classe 2 ne sera pas créée, lS2 pointera vers la mémoire pointée par lS1,
////C'est-à-dire lS1 = lS2end;
deux. Implémentation Delphi de l'exemple dans "Design Patterns"
L'exemple d'implémentation de « Design Pattern » consiste à contrôler une seule instance d'objet via une fonction de constructeur privé. Cependant, l'implémentation du code C++ donnée n'indique pas comment l'objet est publié. La fonction Create ne peut pas être privatisée dans Delphi. Nous définissons une nouvelle fonction pour remplacer la fonction Create et protéger la fonction Create de la classe parent. Le code est le suivant
:
////------------------------------------------------------------ -- --------------------------
////
unité uSingletonUnit ;
interface
utilise
Classes, SysUtils ;
taper
TCSingleton = class(TComponent) ////Hérité de la classe Tcomponent.
privé
constructeur CreateInstance(AOwner: TComponent); ////Passer le paramètre Owner
//// De cette façon, l'objet de classe TCSingleton sera détruit avec le propriétaire (le propriétaire est responsable de la destruction de l'objet TCSingleton)
publique
constructeur Create (AOwner : TComponent );
fonction de classe Instance (AOwner : TComponent) : TCSingleton ;
fin;
var
gCSingleton : TCSingleton ; //// Variables globales
mise en œuvre
{TCSingleton}
constructeur TCSingleton.Create(AOwner : TComponent);
commencer
////Protégez la fonction de création
raise Exception.CreateFmt('accès à la classe %s via l'instance uniquement',
[Nom de classe]);
fin;
constructeur TCSingleton.CreateInstance (AOwner : TComponent) ;
commencer
////Le constructeur nouvellement défini est Private
hérité Create(AOwner);
fin;
fonction de classe TCSingleton.Instance (AOwner : TComponent) : TCSingleton ;
commencer
si ce n'est pas attribué (gCSingleton), alors
gCSingleton := TCSingleton.CreateInstance(AOwner);
Résultat := gCSingleton;
fin;
fin.
////------------------------------------------------------------ -- ----------------------------/
/
Lors de l'utilisation de la classe d'implémentation ci-dessus, les programmeurs n'ont pas besoin d'envisager la destruction des objets en mode singleton. Il ne peut tout simplement pas appeler Create, vous devez appeler la fonction Instance pour obtenir une instance de l'objet et transmettre le propriétaire du singleton en tant que paramètre à la fonction. Cette méthode d'implémentation peut être héritée en tant que classe de base et utilisée dans un singleton du modèle d'état (voir référence 4) pour obtenir un polymorphisme au moment de l'exécution.
trois. Conclusion
L'implémentation Delphi du mode Singleton peut également être trouvée sur Internet. Il existe d'autres méthodes d'implémentation. Les deux méthodes décrites dans cet article sont.
Le plus courant et le plus simple. Dans le même temps, les idées des autres méthodes sont également très similaires à celles des deux méthodes ci-dessus.