Analyse des polymorphismes à Delphi
1 Qu'est-ce que le polymorphisme? 2
1.1 Concept 2
1.2 La signification du polymorphisme 2
1.3 Comment implémenter le polymorphisme à Delphi? 2
1.3.1 Héritage 2
1.3.2 Méthodes virtuelles, méthodes dynamiques et méthodes abstraites, VMT / DMT, liaison statique et liaison dynamique 2
1.3.3 Surcharge et polymorphisme 2
1.4 Discussion sur les espèces polymorphes 2
1.4.1 Polymorphisme à deux niveaux 2
1.4.2 Polymorphisme dangereux 2
2 Applications du polymorphisme dans VCL2
2.1 Méthode de construction et de destruction 2
2.2 TSTRINGS2
2.3 Autres (veuillez ajouter l'âme) 2
Le polymorphisme abstrait est l'âme des objets.
Polymorphisme de mots clés , héritage, orienté objet, VCL, méthode virtuelle, remplacement
question
Le polymorphisme est l'âme de l'objet, et la compréhension du polymorphisme est l'une des clés pour maîtriser la technologie orientée objet. Mais qu'est-ce que le polymorphisme exactement? Quelle est la signification du polymorphisme? Comment réaliser le polymorphisme? Je peux comprendre le concept de polymorphisme, mais je ne sais pas comment l'utiliser et quand l'utiliser? Veuillez lire cet article en détail.
Analyse des experts
Le monde (objet, c'est-à-dire objet) est en train de changer; Eh bien, dans le langage informatique. L'industrie des logiciels entière était en train de secouer la terre. Les outils de développement orientés sont également apparus, tels que VC, Delphi et BCB. La conception orientée (OOD), l'analyse orientée objet (OOA) et la base de données orientée objet (OODB)), la technologie orientée objet a presque pénétré l'ensemble du champ logiciel, et la façon de penser des programmeurs a également subi des changements fondamentaux! Aux yeux de certains théoriciens de la purification OO, tout est un objet! Bien que je ne sois pas tout à fait d'accord avec ce point de vue. Mais je pense que cette méthode est la plus conforme aux habitudes de pensée des gens. Cerveau à partir de ce moment, j'ai été libéré! C'est une révolution!
Le contenu central de l'objet est un objet, une encapsulation, un héritage, un polymorphisme et des messages. Master Polymorphisme, vous ne maîtriserez pas vraiment la technologie orientée objet.
1 Qu'est-ce que le polymorphisme?
1.1 Concept
Il existe de nombreuses opinions différentes sur le concept de polymorphisme, et les éléments suivants sont plusieurs déclarations représentatives:
«Cette capacité à manipuler plus d'un type avec un pointeur ou une référence à une classe de base parle de polymorphisme» (Primer C ++, page 838). Autrement dit, la possibilité d'exploiter des objets de plusieurs classes (classe de base et ses classes dérivées) en utilisant des pointeurs / références aux classes de base est appelée polymorphisme. Il est pris en compte du point de vue de la mise en œuvre du langage.
"Le polymorphisme fournit une autre dimension de séparation de l'interface de la mise en œuvre, pour découpler de quoi" ("penser en Java" 3e édtion), c'est-à-dire que le polymorphisme fournit un autre type d'interface de séparation et d'implémentation (c'est-à-dire à "quoi faire" et «Comment faire une échelle de« séparément ». Il est considéré dans une perspective de conception.
«La capacité d'utiliser la même expression pour désigner différentes opérations est appelée polymorphisme» (Principes de méthodes orientés objet et pratique 3e édition, p. 16). En termes simples, le polymorphisme est "la même expression, différentes opérations", ou on peut dire que "la même commande, différentes opérations". Ceci est du point de vue de la sémantique orientée objet.
Les trois déclarations expliquent l'essence du polymorphisme sous différentes perspectives. La troisième déclaration est particulièrement précise.
Permettez-moi d'expliquer la signification de cette phrase en premier:
Même expression - appel de fonction
Différentes opérations - il y a des opérations différentes selon différents objets.
Par exemple, dans une entreprise, il existe différents employés ayant des responsabilités différentes (programmeurs, vendeurs, gestionnaires de documents, etc.) qui font des choses différentes lorsqu'ils «vont travailler» (peuvent également être considérés comme une sorte de logique commerciale), nous Résumé leur travail respectif comme «travailler», et la relation est la suivante:
personnel
/ | / —— Relation de l'héritage
Gestionnaire de documents du vendeur du programmeur
Une fois les heures de travail tous les jours, cela équivaut à émettre une commande comme celle-ci:
"Employés. Commencez à travailler" (même expression)
Après que chaque employé reçoive cette commande (la même commande), il "commence à fonctionner", mais ce qu'ils font, c'est leur travail respectif, le programmeur commence "coder", le vendeur commence "Contacter Business" et le directeur culturel commençons " Organiser des documents ». Autrement dit, "la même expression (Function Call), différentes opérations (exécuter selon différents objets pendant la période d'exécution)."
Du point de vue de la mise en œuvre du langage du polymorphisme, le polymorphisme est réalisé en appelant sa méthode virtuelle par des pointeurs de classe de base ou des références à des objets pointant vers des classes dérivées. Ce qui suit est la mise en œuvre de la langue pascale objet
Temloyee = classe // les employés abstraits dans une classe abstraite
publique
Procédure Startworking; virtual; Résumé;
{Les fonctions abstraites (c'est-à-dire les fonctions virtuelles pures en C ++), ne font rien, la signification réelle est de réserver d'abord une interface. La surcharge l'implémente dans sa classe dérivée. }
fin;
Tprogrammer = classe (temloyee) // programmeur
publique
Procédure Startworking;
fin;
Tbusinessman = class (temloyee) // vendeur
publique
Procédure Startworking;
fin;
TdocManager = class (temloyee) // Manager de texte
publique
Procédure Startworking;
fin;
procédure tprogrammer.startworking;
Commencer
ShowMessage («codage»);
fin;
{Tbusinessman}
procédure tbusinessman.startworking;
Commencer
ShowMessage («Linking Business»);
fin;
{TDocManager}
procédure tdocmanager.startworking;
Commencer
ShowMessage («Gestion Document»);
fin;
Procédure tform1.button1Click (expéditeur: tobject);
const
enum = 3;
var
Employé: tableau de TEMPloyee;
I: entier;
Commencer
SetLength (employé, enum);
Employee [0]: = TProgrammer.Create;
// Reportez-vous à l'employé de la classe de base [0] pour pointer vers l'objet TProgrammer qui vient d'être créé
Employé [1]: = tbusinessman.Create;
// Reportez-vous à l'employé de la classe de base [1] pour pointer vers l'objet tbusinessman que vous venez de créer
Employee [2]: = TDocManager.Create;
// Reportez-vous à l'employé de la classe de base [2] pour pointer vers l'objet TDocManager
pour i: = 0 à longueur (employé) -1 do
Employé [i] .startworking;
{Dans la perspective du polymorphisme de l'implémentation du langage, le polymorphisme est implémenté en appelant sa méthode virtuelle par pointeur de classe de base ou objet de référence pointant vers des classes dérivées. L'employé [] fait référence à un tableau pour l'objet de classe de base, et ses membres pointent respectivement différents objets de classe dérivés.
fin;
Essayer
Vous pouvez taper certains des programmes de code (ou de démonstration) ci-dessus, compiler et exécuter, et cliquer sur le bouton pour voir l'effet magique du polymorphisme.
1.2 La signification du polymorphisme
La signification de l'encapsulation et de l'héritage est qu'ils implémentent la réutilisation du code, tandis que la signification du polymorphisme est qu'il met en œuvre la réutilisation de l'interface (même expression). capable.
Par exemple, afin de mieux gérer, les programmeurs sont divisés en programmeurs C ++ et programmeurs Delphi. …
personnel
/ | / —— Relation de l'héritage
Gestionnaire de documents du vendeur du programmeur
/ / —— Relation de l'héritage
Programmeur C ++ Delphi Programmer
Une fois que le programmeur a ajouté les deux classes dérivées de TCPPProgrammer et de Tdelphiprogrammer, la méthode d'appel n'a toujours pas changé, et c'était toujours "les employés. Commencer à travailler", qui a été décrit avec Object Pascal:
…
SetLength (employé, enum + 2);
Employee [enum]: = TCPPProgrammer.Create;
// Créez un objet TCPPProgrammer et pointez l'employé de référence de la classe de base [enum]
Employee [enum + 1]: = tdelphiprogrammer.Create;
…
{Secteurs.
pour i: = 0 à longueur (employé) -1 do
Employee [i] .startworking;
…
1.3 Comment implémenter le polymorphisme à Delphi?
Les conditions nécessaires pour réaliser le polymorphisme sont l'héritage, les méthodes virtuelles, la liaison dynamique (ou la liaison du décalage).
1.3.1 Héritage
L'héritage fait référence à la relation "AKO (une sorte de, est a)" entre une classe, comme un programmeur "est un" employé, indiquant une relation d'héritage. À Delphi, seul l'héritage est pris en charge (aucune considération de l'héritage multiple implémenté par les interfaces). Par des objets de classe dérivés (ou vice versa).
indice
Dans UML:
Ako: Une sorte de relation d'héritage signifie
Apo: une partie de représente une relation combinée
ISA: Isa représente la relation entre un objet et une classe à laquelle il appartient.
1.3.2 Méthodes virtuelles, méthodes dynamiques et méthodes abstraites, VMT / DMT, liaison statique et liaison dynamique
Pour toutes les méthodes, il n'y a pas de trace dans l'objet. Son pointeur de méthode (adresse d'entrée) est stocké dans la classe, tandis que le code réel est stocké dans le segment de code. Pour les méthodes statiques (méthodes non virtuelles), le compilateur détermine directement l'adresse d'entrée de la méthode de l'objet basé sur le type de référence de l'objet au moment de la compilation, qui est appelé liaison statique; Le compilateur ne peut pas déterminer la classe réelle à laquelle il appartient, de sorte que l'adresse d'entrée de la méthode ne peut être déterminée que via l'adresse d'entrée de la table VMT (c'est-à-dire les quatre premiers octets de l'objet) pendant l'exécution. bundling de lag).
Méthode virtuelle
Une méthode virtuelle représente une méthode qui peut être remplacée. En plus de stocker son propre pointeur de méthode virtuelle, la classe stocke également le pointeur de méthode virtuelle de toutes les classes de base.
Méthode de déclaration:
Nom de la méthode de procédure;
Cela équivaut à dire au compilateur Delphi:
Cette méthode peut être surchargée dans la classe dérivée, et la méthode virtuelle sera toujours après la surcharge.
Ne déterminez pas l'adresse d'entrée de la méthode pendant la période de compilation. Pendant l'exécution, l'adresse d'entrée de la méthode est déterminée par liaison dynamique.
Fournissez une implémentation par défaut dans la classe de base.
Méthode dynamique
Les méthodes dynamiques et les méthodes virtuelles sont essentiellement les mêmes. Mais cela est complètement transparent pour les utilisateurs.
Méthode de déclaration:
Nom de la procédure; dynamique;
Méthodes abstraites
Une méthode virtuelle spéciale, qui n'a pas besoin de fournir une implémentation par défaut dans la classe de base, est juste utilisée pour une interface d'appel, ce qui équivaut à une fonction virtuelle pure en C ++. Les classes contenant des méthodes abstraites sont appelées classes abstraites.
Méthode de déclaration:
Nom de la procédure; virtuel; résumé;
VMT / DMT
Dans Delphi, la table de méthode virtuelle (VMT) n'est en fait pas physiquement. Méthodes virtuelles de sa classe de base. L'adresse de l'entrée VMT stockée dans les quatre premiers octets de l'objet est en fait l'adresse de la classe à laquelle il appartient (voir le programme de démonstration). Avec la classe réelle, l'adresse de la méthode virtuelle peut être trouvée.
Obj (nom d'objet) la classe à laquelle appartient l'objet réel
Adresse d'entrée VMT
Membres de données
Adresse d'entrée VMT de la classe Virtual Method Table
Informations sur le modèle de membre des données
Méthodes statiques, etc.
Méthode virtuelle (VMT)
Méthode dynamique (DMT)
Figure 3 La relation entre les noms d'objets, les objets et les classes
DMT est similaire à VMT, et est également un concept logique. n'est pas aussi rapide que celui des méthodes virtuelles.
Citez l'exemple ci-dessus pour expliquer:
Employé [i] .startworking;
L'employé [i] est une référence d'objet de la classe de base TempleEyee. Ainsi, l'objet réel ne peut pas être connu pendant la compilation, donc l'adresse de la méthode ne peut pas être déterminée. Pendant la période d'exécution, bien sûr, je connais le "vrai visage de Lushan" de l'objet. La fonction à appeler, c'est-à-dire le polymorphisme est réalisée.
1.3.3 surcharge et polymorphisme
De nombreux internautes croient que la surcharge de la fonction est également une sorte de polymorphisme, mais ce n'est pas le cas. Pour les «opérations différentes», la surcharge ne peut pas fournir la même méthode d'appel. La prémisse de la mise en œuvre du polymorphisme est la même expression! Par exemple, l'employé [i] .Startworing, les appels surchargés ont des paramètres ou des types de paramètres différents. La surcharge n'est qu'un mécanisme de langue, et il y a aussi une surcharge en C, mais C n'a pas de polymorphisme et C n'est pas un langage de programmation orienté objet. À moins que la fonction de surcharge est également une méthode virtuelle, le compilateur peut déterminer l'adresse d'entrée de la fonction en fonction du type de paramètre ou de la liaison statique! Citez le père de C ++, "Ne soyez pas stupide. Si ce n'est pas une liaison dynamique, ce n'est pas le polymorphisme."
1.4 Discussion sur les espèces polymorphes
1.4.1 Polymorphisme à deux niveaux
Niveau d'objet: utilisez le pointeur de base de base / référence pour pointer de son objet de classe dérivé et appeler des méthodes virtuelles (ou méthodes dynamiques, méthodes abstraites), qui est la plus couramment utilisée.
Niveau de classe: utilisez des références de classe (références aux classes plutôt qu'aux objets) pour pointer des classes dérivées, appeler des méthodes de classe virtuelle (ou méthodes de classe dynamique, méthodes de classe abstraite) et sont couramment utilisés dans les polymorphismes créés par des objets (car le constructeur est Une sorte de méthodes de type "pour spécial", veuillez vous référer à mon autre travail "Analyse de la structure et de la destruction à Delphi", section 2.1).
indice
La référence de classe est une variable de référence de la classe elle-même, pas une classe, ni une référence d'objet. Tout comme le nom d'objet représente une référence d'objet, le nom de classe représente une référence de classe, car dans Delphi, la classe est également traitée comme un objet. Un type de référence de classe est le type d'une référence de classe et la méthode de déclaration d'un type de référence de classe:
Nom du type de référence de classe = classe de nom de classe
Nous pouvons voir de nombreuses déclarations de référence de classe dans le code source VCL, telles que:
Tclass = classe de tobject;
TComponentClass = classe de tComponent;
TControlClass = classe de tControl;
Avis
Dans une méthode de classe, l'auto-implicite dans la méthode est une référence de classe, pas une référence d'objet.
1.4.2 Polymorphisme dangereux
Le polymorphisme peut également être mis en œuvre en utilisant des pointeurs de classe dérivés aux objets de classe de base! Bien que ce soit une mauvaise façon de l'utiliser:
Procédure tform1.btnbadpolyclick (expéditeur: tobject);
var
CPPProgrammer: TCPPProgrammer; // Définir une référence du programmeur CPP, une référence à une classe dérivée!
Commencer
{*****************************déclaration******************* ******************
Polymorphisme implémenté avec des pointeurs de classe dérivés / références aux objets de classe de base. C'est un polymorphisme pathologique!
Cette méthode polymorphe est comme une très petite chose (objet de classe de base) recouvert d'un puissant
L'apparition du produit (références de classe dérivées) apporte ainsi de nombreux facteurs d'insécurité potentiels (tels que les exceptions d'accès), donc
Avec presque aucune valeur. "Fichier" Un exemple vise à illustrer la nature du polymorphisme à Delphi, la nature du polymorphisme: utilisez un pointeur légal (généralement la classe de base) / référence pour faire fonctionner l'objet, selon l'objet réel pendant l'exécution, pour exécuter différentes opérations Méthodes, ou à une déclaration plus vive: l'objet lui-même décide sa propre méthode de fonctionnement. l'objet. Cela permet la séparation des interfaces et des implémentations, ce qui rend possible la réutilisation de l'interface.
**************************************************** ******* ***********************************}
CPPProgrammer: = TCPPProgrammer (TProgrammer.Create);
{Afin d'atteindre ce polymorphisme pathologique, la référence d'objet est jetée au type TCPPProgrammer,
Échappe ainsi à la vérification du compilateur}
cppprogrammer.startworking;
{Tprogrammer.startworking appelé au lieu de tcppprogrammer.startworking
Il s'agit du polymorphisme mis en œuvre avec des pointeurs de classe dérivés / références à l'objet de classe de base. }
cppprogrammer.free;
CPPProgrammer: = TCPPProgrammer (tDocManager.Create);
cppprogrammer.startworking;
{L'appel est tdocmanager.startworking,
Il s'agit du polymorphisme mis en œuvre avec des pointeurs de classe dérivés / références à l'objet de classe de base. Cette méthode est extrêmement dangereuse.
Et il n'y a pas besoin}
cppprogrammer.free;
fin;
Essayer
Afin d'obtenir ce type de compréhension perceptuelle du polymorphisme, il est recommandé de l'essayer. ? Dans quelles circonstances une exception d'accès se produira-t-elle? (Reportez-vous au programme de démonstration)
2 Applications du polymorphisme dans VCL
2.1 Méthodes de construction et de destruction
Polymorphisme de la méthode de construction
Étant donné que le constructeur peut être considéré comme une méthode de classe "spéciale", toutes les classes dérivées après le Tomponent sont redéfinies en tant que méthodes de classe virtuelle, donc pour réaliser le polymorphisme du constructeur, vous devez utiliser des références de classe. Dans chaque fichier de projet, il existe un code similaire à ce qui suit:
application.CreateForm (TForm1, Form1);
Définition de sa méthode:
Procédure Tapplication.CreateForm (instanceClass: tComponentClass; Var Reference);
var // instanceClass est une référence de classe.
Instance: tComponent;
Commencer
Instance: = tComponent (instanceClass.NewInstance);
{Méthode NewInstance: Fonction de classe NewInstance: Tobject; InstanseClass est une référence de classe qui met en œuvre le polymorphisme au niveau de la classe, réalisant ainsi la réutilisation de l'interface pour la création de composants}
TComponent (référence): = instance;
essayer
Instance.create (self); // appelle le constructeur pour l'initialiser
sauf
TComponent (référence): = nil; // éliminer le pointeur "sauvage"! bien
augmenter;
fin;
{Si la fenêtre créée et il n'y a pas encore de formulaire principal, définissez le formulaire juste créé comme formulaire principal}
if (fmainform = nil) et (instance est tform) alors
Commencer
Tform (instance) .Handleneeded;
Fmainform: = tform (instance); // définir le formulaire principal
{En fait, la définition du formulaire principal dans les options de projet (Project-> Options) est en fait l'instruction de formulaire correspondant dans le fichier du projet avant toutes les instructions de création de formulaire. }
fin;
fin;
2) Pour le polymorphisme de la méthode destructuration, veuillez vous référer à "Analyse de la structure et de la destruction à Delphi", section 3.3
2.2 TSTRINGS
Le traitement du tableau des chaînes est très courant dans les commandes de Delphi, généralement avec certains attributs d'éléments, qui sont particulièrement pratiques à utiliser (car ils utilisent tous la même interface), grâce à la conception de l'architecture de tableau de chaînes à Delphi. Ceci est un design réussi.
Étant donné que de nombreux contrôles utilisent des réseaux de chaînes, tels que ComboBox, TStringGrid, etc., mais les tableaux de chaîne dans chaque contrôle sont différents, Delphi résume les tableaux de chaîne, donc de nombreuses classes connexes apparaissent. La classe de base TStrings fournit uniquement une interface pour divers appels, et l'implémentation spécifique peut être implémentée entièrement à partir de ses classes dérivées.
Jetons un coup d'œil à la définition des méthodes communes de la classe TStrings de la classe de base (voir la ligne d'unité des classes 442):
TStrings = classe (tPesistent)
protégé
...
Fonction Get (index: entier): String;
procédure put (index: entier; const s: string);
Fonction GetCount: entier;
…
publique
Fonction Add (const S: String): entier;
{Ajouter une chaîne S à la fin de la liste des chaînes}
procédure addStrings (chaînes: tStrings);
{Ajouter des chaînes à la fin de la liste des chaînes}
Insert de procédure (index: entier; const S: String);
{Méthode abstraite, insérez une nouvelle chaîne S en position d'index}
procédure claire;
{Effacer toutes les chaînes}
Procédure Supprimer (index: entier);
{Supprimer une chaîne à un certain emplacement}
Index de fonction (const S: String): entier;
{Obtenez la position de S dans la liste des chaînes}
Fonction indexofName (const name: String): entier;
{Renvoie la position de la première chaîne avec le nom de formulaire = valeur avec la pièce de nom spécifiée}
Fonction IndexofObject (AObject: TOBject): entier;
{Obtenez la position de l'objet avec l'objet nommé AObject: dans la liste des chaînes}
Procédure LoadFromFile (const FileName: String);
{Remplit la liste des lignes de texte dans un fichier spécifié}
Procédure LoadFromStream (Stream: TStream);
{Remplit la liste de lignes de texte lues à partir d'un flux}
Procédure SaveToStream (Stream: TStream);
{Écrit la valeur de la propriété texte à un objet Stream}
Strings de propriété [Index: entier]: String Read Get Write Put;
{Référence les chaînes dans la liste par leurs positions}
Valeurs de propriétés [const name: String]: String Read GetValue Write SetValue;
{Représente la partie de valeur d'une chaîne associée à un nom donné, sur les chaînes avec le nom de formulaire = valeur.}
…
fin;
D'après la définition des TStrings, on peut voir que la plupart de ses méthodes protégées et publiques sont des méthodes virtuelles ou des méthodes abstraites. (Veuillez en ajouter quelques-uns, tStringList-> tStringgridString)
2.3 Autres (veuillez ajouter l'âme)
Si vous ne comprenez pas encore le polymorphisme, n'oubliez pas l'essence du polymorphisme:
"Même expression, opérations différentes" (c'est aussi simple)
Du point de vue de la mise en œuvre du langage OOP, le polymorphisme consiste à utiliser le pointeur / référence de la classe de base pour opérer (classe dérivée) et effectuer différentes méthodes de fonctionnement en fonction de l'objet réel pendant la période d'exécution; Une déclaration plus vive: l'objet décide de sa propre méthode de fonctionnement. lui-même. Cela permet la séparation des interfaces et des implémentations, ce qui rend possible la réutilisation de l'interface.
En fait, le polymorphisme est simple! Alors, à quoi devriez-vous prêter attention lors de l'utilisation du polymorphisme? Voici mes deux suggestions:
Analyser la logique métier, puis résumer les choses liées à des "objets", puis encapsuler la logique métier à l'aide de méthodes d'objets. Déclarez certaines opérations avec le polymorphisme comme méthodes virtuelles dans la classe de base, et déclarez-les comme des méthodes abstraites virtuelles pour ceux qui ne sont pas nécessaires pour mettre en œuvre dans la classe de base, puis les surcharger dans leurs classes dérivées. / pointeurs de la classe de base lorsqu'ils sont utilisés, ce qui réalise naturellement le polymorphisme dans le monde réel. N'oubliez pas de ne pas atteindre le polymorphisme pour le bien du polymorphisme.
Puisqu'il existe une relation naturelle de "couplage" entre les classes de base et les classes dérivées, la modification des classes de base conduira à "atteindre le corps entier", ce qui sera très gênant! Par conséquent, nous devons essayer d'affaiblir la mise en œuvre fonctionnelle de la classe de base, de la concevoir comme une "classe abstraite" si nécessaire, et d'assurer une interface stable.
Questions connexes
Discutez du polymorphisme de Delphi: http://www.delphhibbs.com/delphhibbs/dispq.asp?lid=1753965
À propos du polymorphisme: http://www.delphhibbs.com/delphhibbs/dispq.asp?lid=1854895
Qu'est-ce que le polymorphisme? Quelles sont les utilisations de la programmation quotidienne? http://www.delphibbs.com/delphibbs/dispq.asp?lid=960465
Quelle est la différence entre la surcharge et la priorité? http://www.delphibs.com/delphibs/dispq.asp?lid=296739
Problème que le pointeur de la classe dérivée pointe vers l'objet de classe de base http://www.delphibs.com/delphibs/dispq.asp?lid=2104106
(La dernière question a été mentionnée sur Delphibbs lorsque j'étudiais profondément le polymorphisme, ce qui a provoqué une discussion animée. Je vous suggère de jeter un œil)