C'est un concept que je vais avoir du mal à assimilerhaha mais c'est l'unité qui est un singleton à elle seule
C'est un concept que je vais avoir du mal à assimilerhaha mais c'est l'unité qui est un singleton à elle seule
Mes tutoriels
Avant de poster :
- F1
- FAQ
- Tutoriels
- Guide du développeur Delphi devant un problème
Bonjour,
Discussion passionnante entre experts qui ne sont pas toujours d'accord, on se croirait sur un plateau télé.
Autodidacte complet en matière de développement informatique (j'ai commencé en basic puis avec Delphi 1), il me manque certainement les bases, mais je me pose la question à quoi sert un singleton ?
Pourquoi mettre une déclaration de class à l'intérieur d'une déclaration de class ? On peut me répondre pourquoi pas !!
J'ai créé mes propres objets mais je n'ai jamais eu ce besoin...
Merci de m'éclairer
Si c'est trop compliqué ou trop basique laissez tomber...
Mon tutoriel explique justement à quoi sert un singleton.
Mettre une déclaration de classe à l'intérieur d'une déclaration de classe permet de déclarer une classe interne à celle ci. On la déclare généralement en privée pour la rendre visible uniquement par la classe dans laquelle elle est déclarée (sinon ça ne sert pas à grand chose selon moi, autant la déclarer ailleurs). Ce n'est pas possible avec Delphi 7 mais cela se rencontre dans des langages plus évolués tel que C# (ou peut être sous XE, il faut vraiment que je l'essaie celui-la).
Comme tout le monde, j'ai commencé avec des applications consoles et du procédural. Mais j'ai toujours vu une unité comme un simple nom sous lequel on regroupait telles classes et/ou telles procédures et fonctions. Je n'ai jamais placé le nom de l'unité devant le nom d'une variable d'un objet ou d'une fonction à moins d'y être obligé (c'est à dire quand delphi détecte un nom ambigu).Envoyé par Paul TOTH
En gros, je vois ta variable PublicValue comme une simple variable globale et non comme un élément dans un singleton.
Mes tutoriels
Avant de poster :
- F1
- FAQ
- Tutoriels
- Guide du développeur Delphi devant un problème
je suis aussi autodidacte en fait et j'ai commencé par QBASIC en fait nom par le BASIC du Commodore 64 ^^
ceci dit, la notion de Singleton fait référence aux design patterns. L'idée c'est qu'au lieu de réinventer la roue à chaque nouveau projet, tu te contentes d'identifier dans ton projet des patrons bien définis qu'il suffit alors d'appliquer "bêtement" car ils ont été bien pensés et si tu utilises des objets qui suivent ces patrons tu sais que ton application réagit de la façon attendue.
Exemple, si je considère que la connexion à la base de donnée est un singleton, j'applique ce principe à l'objet de connexion...Delphi avec ses DataModule et composants de connexion n'est pas adapté d'ailleurs pour suivre cette méthodologie.
en tant que développeur expérimenté tu sais que le DataModule en question n'est instancié qu'une fois, qu'il est présent tout au long de la durée de vie du projet et tu l'utilises "comme" un singleton. Mais ça ne fonctionne que parce que tu prends soins de l'instancier au départ et de ne jamais le détruire, l'objet lui même ne te garantit pas ce fonctionnement. Implémenter le pattern Singleton c'est faire en sorte que ce DataModule ne puisse être instancié qu'une seule fois même si je tente d'appeler deux fois TDataModule1.Create
EDIT: ceci dit, même sans utiliser des objets qui supportent ces design patterns, il n'est pas inutile de les connaitre car ils répondent effectivement à pas mal de problématiques objet et tu peux concevoir (tu le fais sans doute déjà en partie) tes projets avec ces notions en tête, et ça permet de partager le même vocabulaire avec d'autres développeurs : "ça c'est un Singleton" définit précisément le fonctionnement de l'objet sans avoir besoin de l'expliquer (l'implémentation elle est secondaire).
Bonjour,
Le tutoriel de Jeremy comporte au moins une erreur sur l'implémentation sur une version récente de Delphi.
TMyObjet, à cause de la présence de "Class var" et "Class function" est instancié au lancement du programme. Donc l'exemple montré crée deux instances de TMyObjet
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 TMyObject = class class var Instance: TMyObject; class function GetInstance: TMyObject; end;
Ce que l'onpeux voir en utilisant un code comme "integer(pointer(self))". Donc de fait une "Class" qui ne comporte que des Class var, Class Function, Class .... est de fait un singleton
GetInstance peut s'écrire comme suit :
Par contre penser à inhiber si besoin est le Constructor Create
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 function TMyObject.GetInstance: TMyObject; begin Result := self ; end;
Merci à la modération d'avoir déplacé ce message depuis Le patron de conception "Interpréteur" avec Delphi 7, un tutoriel de Jérémy Laurent
Le tutoriel sur le Singleton a 5 ans, c'est pas le sujet du jour mais tes remarques ont un intérêt
Une instance ?
J'espère que non, car si j'ai une seule "class var" dans une classe contenant beaucoup de membres, même si aujourd'hui la mémoire n'est pas un problème, cela semble maladroit d'allouer l'espace mémoire d'une instance pour la MetaClass
D'ailleurs, lors de l'ajout d'un "class var", l'InstanceSize de l'objet n'augmente pas j'espère, on peut espérer que cela soit un pointeur partagé sur un emplacement commun
J'ai du mal à comprendre ce lien entre MetaClass et une sorte d'instance fantôme que tu évoques !
Tu peux faire une démonstration ?
Dans une méthode de class, tu sais reconnaître l'adresse mémoire d'une MetaClass de l'adresse mémoire d'une Instance ?
Tu peux expliquer !
et surtout quelle version ?
On peut surtout penser que c'est un exemple, en l'absence de générique, en D7, tu dois donc mettre le code de gestion du singleton dans la classe, donc tu n'as jamais cette forme minimale de TMyObjet, c'est à prendre comme un template
Ce n'est plus méthode de classe ? comment l'invoquer ?
Si c'est une méthode d'instance, tu le fais via une variable locale mais du coup, comme l'initialiser ?
Tu peux faire une démonstration ?
Petite démonstration qui montre que Self prend la valeur qu'on lui donne (ou qu'on oublie de lui donner)
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 type TMyObject = class class var Instance: TMyObject; class function GetInstance: TMyObject; class function GetInstance2: TMyObject; function GetInstance3: TMyObject; end; class function TMyObject.GetInstance: TMyObject; begin if Instance = nil then Instance := TMyObject.Create; Result := Instance; ShowMessage(integer(pointer(self)).ToString()); end; class function TMyObject.GetInstance2: TMyObject; begin // Result := Self ; // ne compile pas évidemment, MetaClass contre Instance ShowMessage(integer(pointer(self)).ToString()); end; function TMyObject.GetInstance3: TMyObject; begin Result := Self ; ShowMessage(integer(pointer(self)).ToString()); end; procedure TForm1.Button4Click(Sender: TObject); var o: TMyObject; begin o.GetInstance3(); ShowMessage(integer(pointer(o)).ToString()); o := nil; o.GetInstance3(); ShowMessage(integer(pointer(o)).ToString()); end;
Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
Attention Troll Méchant !
"Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
L'ignorance n'excuse pas la médiocrité !
L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
Il faut avoir le courage de se tromper et d'apprendre de ses erreurs
voir le pdf associé
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 . . . type TDemo = class private class var fV2 : integer ; public V1 : integer ; class property ClassV2 : integer read fv2 write fv2 ; function func1 : string ; class function classfunc2 : string ; class function classfunc3 : string ; end; var aDemo : TDemo ; function TDemo.func1: string; begin v1 := integer(pointer(self)) ; fv2 := fv2 + 1 ; result := intToHex (V1,8) end; class function TDemo.classfunc2: string; begin fv2 := integer(pointer(self)) ; result := intToHex (fv2,8) end; class function TDemo.classfunc3: string; begin fv2 := fv2 + 1 ; result := intToHex (ClassV2,8) ; end; begin writeln (TDemo.classfunc3) ; writeln (TDemo.classfunc3) ; aDemo := TDemo.Create ; writeln (aDemo.func1) ; writeln (aDemo.classfunc3) ; writeln (aDemo.classfunc3) ; writeln (aDemo.classfunc2) ; FreeAndNil (aDemo) ; writeln (TDemo.classfunc2) ; writeln (intToHex(TDemo.ClassV2,8)) ; readln ; end.
Merci à la modération d'avoir déplacé ce message depuis Le patron de conception "Interpréteur" avec Delphi 7, un tutoriel de Jérémy Laurent
Et que montre ce PDF ?
Je ne vois pas de démonstration d'une instance fantôme, juste qu'il y a des "Champs de classe" et de l'autres les "champs d'instance";
Evoquer une instance pour le stockage des "Champs de classe" est très maladroit et une erreur de première dans un cours.
Et cela ne démontre aucunement une erreur sur le Singleton désigné plus haut, juste un choix d'avoir une instance unique au lieu d'utiliser uniquement des "Champs de classe".
Avoir une instance d'ailleurs permet de passer à un Multiton (+Factory) de façon beaucoup plus transparente
Sinon comme démontrer cette théorie de l'instance fantome avec l'héritage
M est partagé par TDemo et TDemo2, l'un modifie l'autre
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 type TDemo = class private class var M: Integer; public class function IncM(): string; end; TDemo2 = class(TDemo) private class var K: Integer; public class function IncK(): string; end; { TDemo } class function TDemo.IncM(): string; begin Inc(M); Result := M.ToString(); end; { TDemo2 } class function TDemo2.IncK(): string; begin Inc(M); Inc(K); Result := K.ToString(); end; procedure TForm1.Button5Click(Sender: TObject); begin Memo.Lines.Add('M: ' + TDemo.IncM()); Memo.Lines.Add('M: ' + TDemo.IncM()); Memo.Lines.Add('M: ' + TDemo.IncM()); Memo.Lines.Add('M: ' + TDemo2.IncM()); Memo.Lines.Add('K: ' + TDemo2.IncK()); Memo.Lines.Add('M: ' + TDemo2.IncM()); Memo.Lines.Add('K: ' + TDemo2.IncK()); Memo.Lines.Add('M: ' + TDemo2.IncM()); end;
Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
Attention Troll Méchant !
"Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
L'ignorance n'excuse pas la médiocrité !
L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
Il faut avoir le courage de se tromper et d'apprendre de ses erreurs
Mes tutoriels
Avant de poster :
- F1
- FAQ
- Tutoriels
- Guide du développeur Delphi devant un problème
Je parlais de l'exemple que tu cites en début de ton tutoriel :
Ceci dit cette histoire de singleton me pose problème en Delphi dont les paradigmes sur la POO sont fondamentalement différents de ceux proposé dans des univers comme Java
Voir le lien ci dessous de l'un des concepteurs de Delphi
https://blog.marcocantu.com/blog/202...rcocantu.blog)
Etant malheureusement obligé d'utiliser Delphi 7, je n'ai pas eu l'occasion de travailler avec les classes statiques sur un Delphi moderne.
Je sais qu'en C# s'il n'existe pas de constructeur sans paramètres sur une classes, le compilateur va automatiquement en ajouter un.
Il sera public sur un classe normale, protégé sur une classe abstraite et privé sur une classe statique.
Toujours en C# Sur une classe statique, on a un avertissement à la compilation disant qu'il vaudrait mieux ajouter un constructeur privé.
Cela est dû à la CLR qui va appeler le constructeur sans paramètre avant la création de la première instance de ladite classe.
Je suppose qu'il doit exister la même mécanique sur un Delphi moderne.
Donc ce qu'il manquerait à cet exemple utilisant "class var", c'est un constructeur privé.
Mais cette implémentation simpliste du singleton n'est pas conseillée en C# alors j'ignore ce qu'il est en sur un Delphi moderne.
Edit :
Après une petite recherche j'ai vu que Lazy<T> existe aussi sur Delphi depuis 2013 ainsi que "class constructor"
Donc le code ci-dessous issu de cette page => https://jlambert.developpez.com/tuto...gleton-csharp/
Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 public sealed class Singleton { private static readonly Lazy<Singleton> lazy = new Lazy<Singleton>(() => new Singleton()); public static Singleton Instance { get { return lazy.Value; } } private Singleton() { } }
Ne pourrait-il pas ce traduire par quelque chose de ce genre dans un delphi moderne (écrit à la volée) ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 TSingleton = class private class var FLazy: Lazy<TSingleton>; class function GetInstance(); class constructor Create(); public property Instance: IExampleService read GetInstance; end; class constructor TSingleton.Create; begin FLazy := Lazy<TSingleton>.Create; end; class function TSingleton.GetInstance(); begin Result := FLazy.Value end;
Mes tutoriels
Avant de poster :
- F1
- FAQ
- Tutoriels
- Guide du développeur Delphi devant un problème
Lazy<T> en Delphi depuis 2013 ?
Lazy cela n'existe pas en standard !
Mais je suppose que c'est amalgame pour désigner les génériques et l'on reprendrait ainsi tout ce que l'on a déjà dit il y a 5 ans puisque l'on avait débattu sur le sujet avant rédaction et après rédaction du tutoriel.
une proposition en PROD depuis 2013 Design Pattern : Singleton - Découverte des Génériques et Class Constructor et massivement utilisé car les applications que je développais dans mon ancienne boite commençait par un Singleton qui enrichissait Application (qui est un Singleton aussi typiquement façon D7, une simple variable globale, une instanciation dans une section initialization)
Ce blog pour les non anglophiles, même avec Google Translate, on ne voit rien contre le Singleton
et puis l'édude TApplication pour la VCL mais aussi en FMX Desktop montre un Singleton tel que je l'évoquais du plus primaire, exemple repris par Popo
l'objet TPrinter et son singleton via la fonction Printer() qui utilise une Méta-Classe pour une fabrique dynamique selon l'OS, sans avoir besoin du vocabulaire pompeux de Design Pattern, Singleton est souvent assimilé à une instance globale.
Rien ne vaut les unités systèmes pour connaître les bases et fondamentaux.
La force du Singleton dans FMX prend tout son sens, c'est parfaitement POO, cela exploite le Polymorphisme, c'est une Encapsulation dont le développeur n'a pas forcément besoin de connaître l'implémentation différente sur chaque OS.
TEncoding est intéressant aussi, la classe donne accès à un Singleton par descendant de TEncoding, inspiré par le Dot Net, c'est n'est pas Multition ni vraiment une Strategy, ça fait penser à une Registry mais au lieu d'utiliser une liste ouverte c'est un ensemble fini de propriété.
Je serais curieux de savoir si il existe une pattern pour décrire TEncoding avec ses Singletons multiples ?
TEncoding est d'ailleurs ThreadSafe via AtomicCmpExchange pour protéger l'écriture dans les six class var .
Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
Attention Troll Méchant !
"Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
L'ignorance n'excuse pas la médiocrité !
L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
Il faut avoir le courage de se tromper et d'apprendre de ses erreurs
Bonjour à tous, pour continuer la discussion sur le sujet
J'ai regardé Wikipédia sur le thème "Programmation Orientée Objet" pas de trace de Delphi ni de Pascal Objet
De même pas de POO dans les manuels Delphi 5 ou Delphi 2005.
Si vous trouvez des traces sur le moment de l'apparition de la thématique POO dans Delphi, je suis preneur.
Je crois avoir déjà eu une discussion avec les même protagonistes sur le sujet en 2015 ...
Effectivement, j'ai été un peu vite en besogne.
Je l'ai trouvé dans l'article ci-dessous et n'ai pas réalisé qu'il s'agissait d'un Framework écrit pour Delphi (Spring) et non d'un standard
https://delphisorcery.blogspot.com/2...practices.html
Très intéressante, cette classe TEncoding
On a peu près les même concepts que ce qu'on retrouve en C#
Par exemple pour GetUTF8 :
- une méthode statique renvoyant un type abstrait
- un test d'assignation
- une création si pas assigné
- une mécanique pour garantir un accès Thread Safe
- Et bien entendu [T]UTF8Encoding héritant de [T]Encoding
Code Delphi : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 class function TEncoding.GetUTF8: TEncoding; var LEncoding: TEncoding; begin if FUTF8Encoding = nil then begin LEncoding := TUTF8Encoding.Create; if AtomicCmpExchange(Pointer(FUTF8Encoding), Pointer(LEncoding), nil) <> nil then LEncoding.Free; {$IFDEF AUTOREFCOUNT} FUTF8Encoding.__ObjAddRef; {$ENDIF AUTOREFCOUNT} end; Result := FUTF8Encoding; end;
Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 public static Encoding UTF8 { get { if (utf8Encoding == null) utf8Encoding = new UTF8Encoding(true); return utf8Encoding; } } private static volatile Encoding utf8Encoding;
Mes tutoriels
Avant de poster :
- F1
- FAQ
- Tutoriels
- Guide du développeur Delphi devant un problème
Et pourtant Delphi (ou plutôt Turbo Pascal à l'époque) est orienté POO depuis 1989 !
https://fr.wikipedia.org/wiki/Pascal_(langage)
Il y a même encore le manuel sur le site d'embarcadero
https://edn.embarcadero.com/article/..._OOP_Guide.pdf
Mes tutoriels
Avant de poster :
- F1
- FAQ
- Tutoriels
- Guide du développeur Delphi devant un problème
Bonjour,
Dans mon Manuel de prise en main de D6 Perso, en Introduction, "Qu'est-ce que Delphi ?" :
Et le Guide du langage qui l'accompagne s'intitule "Pascal Objet".Delphi est un environnement de programmation visuel orienté objet pour le développement rapide d'applications (RAD).
Delphi 5 Pro - Delphi 11.3 Alexandria Community Edition - CodeTyphon 6.90 sous Windows 10 ; CT 6.40 sous Ubuntu 18.04 (VM)
. Ignorer la FAQ Delphi et les Cours et Tutoriels Delphi nuit gravement à notre code !
j'ai sous les yeux le Guide du langage D2 avec le même intitulé
par contre je ne trouve pas de manuel de prise en main (de D2,D3)
La POO fait même l'objet d'un chapitre entier (chapitre 7) du guide de l'utilisateur D2
Dans le manuel D5 "guide du développeur" il est indiqué :Envoyé par ALWEBER
Je regarderai bien les manuels D1 mais ils sont en bas d'une pile énormepage 2-1 Le Pascal Objet qui est constitué d'un ensemble d'extensions orientés objet du pascal standard est le langage de Delphi.
page 2-2 La programmation objet (POO)...
Conclusion : Wikipédia est à mettre à jour
MVP Embarcadero
Delphi installés : D3,D7,D2010,XE4,XE7,D10 (Rio, Sidney), D11 (Alexandria), D12 (Athènes)
SGBD : Firebird 2.5, 3, SQLite
générateurs États : FastReport, Rave, QuickReport
OS : Window Vista, Windows 10, Windows 11, Ubuntu, Androïd
Je connais ces manuels puisque je pratique turbo pascal depuis ses origines (1983). Je travaillais à l'époque sur un PC Dual boot : MS-DOS/CPM 86. Quand on parle de POO on pense Smalltalk et descendants. Je cite un chapitre de ce manuel :
A note to you who have done object-oriented programming in other languages:
Put aside your previous impressions of OOP and learn Turbo Pascal 5.5’s object-oriented features on their own terms. OOP is not one single way;
it is a continuum of ideas. In its object philosophy, Turbo Pascal 5.5 is more like C++ than Smalltalk. Smalltalk is an interpreter, while from the beginning,
Turbo Pascal has been a pure native code compiler. Native code compilers do things differently (and far more quickly) than interpreters. Turbo
Pascal was designed to be a production development tool, not a research tool
Ensuite j'ai suivi (avec succès) les cours du CNAM pour comprendre le paradigme de la POO tel qu'il est enseigné pour UML. Les termes sont similaires (Héritage, Encapsulation,Polymorphisme,...) mais les réalités que recouvrent ces termes sont différentes .
Si tu le souhaites on peut reprendre pas à pas tous ces termes
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager