Aller au contenu principal
Version : 21 R3 BETA

Classes

Vue d’ensemble

Le langage 4D prend en charge le concept de classes. Dans un langage de programmation, l'utilisation d'une classe vous permet de définir le comportement d'un objet avec des propriétés et des fonctions associées.

Une fois qu'une classe utilisateur est définie, vous pouvez instancier des objets de cette classe n'importe où dans votre code. Chaque objet est une instance de sa classe. Chaque objet est une instance de sa classe.

Les modèles de classe 4D et JavaScript sont similaires, et basés sur une chaîne de prototypes.

Par exemple, vous pouvez créer une classe Person avec la définition suivante :

//Class: Person.4dm
Class constructor($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname

Function get fullName() -> $fullName : Text
$fullName:=This.firstName+" "+This.lastName

Function sayHello() -> $welcome : Text

$welcome:="Hello "+This.fullName

Dans une méthode, créons une "Person" :

var $person : cs.Person //objet de classe Person
var $hello : Text
$person:=cs.Person.new("John";"Doe")
// $person:{firstName: "John"; lastName: "Doe"; fullName: "John Doe"}
$hello:=$person.sayHello() //"Hello John Doe"

Les fichiers de classe sont gérés via l'Explorateur 4D (voir Créer des classes).

Supprimer une classe

Pour supprimer une classe existante, sélectionnez-la dans l'explorateur et cliquez sur ou choisissez Déplacer vers la corbeille dans le menu contextuel.

Vous pouvez également supprimer le fichier de classe .4dm du dossier "Classes" de votre disque.

Class stores

Les classes disponibles sont accessibles depuis leurs class stores. Il existe deux class stores dans 4D :

  • cs pour le class store utilisateur
  • 4D pour le class store intégré

cs

cs : Object

ParamètresTypeDescription
classStoreObjectClass store utilisateur utilisateurs pour le projet ou le composant

La commande cs retourne le class store utilisateur pour le projet ou le composant courant. Elle retourne toutes les classes utilisateur définies dans le projet ou le composant ouvert. Par défaut, seules les classes ORDA du projet sont disponibles.

Exemple

Vous souhaitez créer une nouvelle instance d'un objet de myClass :

$instance:=cs.myClass.new()

4D

4D : Object

ParamètresTypeDescription
classStoreObjectClass store 4D

La commande 4D retourne le class store des classes 4D intégrées disponibles. Elle donne accès à des API spécifiques telles que CryptoKey.

Exemples

Vous souhaitez créer une nouvelle clé dans la classe CryptoKey :

$key:=4D.CryptoKey.new(New object("type";"ECDSA";"curve";"prime256v1"))

Vous voulez lister les classes 4D intégrées :

 var $keys : Collection
$keys:=OB Keys(4D)
ALERT("There are "+String($keys.length)+" built-in classes.")

L'objet class

Lorsqu'une classe est définie dans le projet, elle est chargée dans l'environnement de langage 4D. Une classe est un objet lui-même de la classe "Class". Un objet classe possède les propriétés et fonctions suivantes :

De plus, un objet classe peut référencer un objet constructor (facultatif).

Un objet classe lui-même est un objet partagé et est donc accessible simultanément à partir de différents process 4D.

Héritage

Si une classe hérite d'une autre classe (c'est-à-dire que le mot-clé Class extends est utilisé dans sa définition), la classe parente est sa superclass.

Quand 4D ne trouve pas une fonction ou une propriété dans une classe, elle la recherche dans sa superclass; si elle n'est pas trouvée, 4D continue la recherche dans la superclass de la superclass, et ainsi de suite, jusqu'à ce qu'il n'y ait plus de superclass (tous les objets héritent de la superclass "Object").

Mots-clés de classe

Des mots-clés 4D spécifiques peuvent être utilisés dans les définitions de classe :

  • Function <Name> pour définir les fonctions de classe des objets.
  • Class constructor pour initialiser les nouveaux objets de la classe.
  • property pour définir les propriétés statiques des objets d'un type donné.
  • Function get <Name> et Function set <Name> pour définir les propriétés calculées des objets.
  • Class extends <ClassName> pour définir l'héritage.
  • This et Super sont des commandes qui ont des fonctionnalités spéciales dans les classes.

Function

Syntaxe

{local | server} {shared} Function <name>({$parameterName : type; ...}){->$parameterName : type}
// code
note

Il n'y a pas de mot-clé de fin pour le code d'une fonction. Le langage 4D détecte automatiquement la fin du code d'une fonction par le mot clé Function suivant ou la fin du fichier de classe.

Les fonctions de classe sont des propriétés spécifiques de la classe. Ce sont des objets de la classe 4D.Function. Dans le fichier de définition de classe, les déclarations de fonction utilisent le mot-clé Function suivi du nom de la fonction.

Si les fonctions sont déclarées dans une classe partagée, vous pouvez utiliser le mot-clé shared avec elles afin qu'elles puissent être appelées sans structure Use...End use. Pour plus d'informations, consultez le paragraphe sur les fonctions partagées ci-dessous.

Dans le contexte d'une application client/serveur, le mot-clé local ou server permet de spécifier sur quelle machine la fonction doit être exécutée. Ces mots-clés ne peuvent être utilisés qu'avec les fonctions du modèle de données ORDA et les fonctions singleton partagées/session. Pour plus d'informations, reportez-vous au paragraphe fonctions locales et serveur ci-dessous.

Le nom de la fonction doit être conforme aux règles de nommage des objets.

note

Étant donné que les propriétés et les fonctions partagent le même espace de nommage, il n'est pas permis d'utiliser le même nom pour une propriété et une fonction de la même classe (une erreur est générée dans ce cas).

tip

Si vous préfixez le nom d'une fonction par un trait de soulignement ("_"), elle ne sera pas proposée par les fonctionnalités d'auto-complétion dans l'éditeur de code 4D. Par exemple, si vous déclarez Function _myPrivateFunction dans MyClass, elle ne sera pas proposée dans l'éditeur de code lorsque vous tapez "cs.MyClass. ".

Immédiatement après le nom de la fonction, des paramètres peuvent être déclarés pour la fonction avec un nom et un type de données, y compris le paramètre de retour (facultatif). Par exemple :

Function computeArea($width : Integer; $height : Integer)->$area : Integer

Dans une fonction de classe, la commande This est utilisée comme instance d'objet. Par exemple :

Function setFullname($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname

Function getFullname()->$fullname : Text
$fullname:=This.firstName+" "+Uppercase(This.lastName)

Pour une fonction de classe, la commande Current method name retourne: <ClassName>.<FunctionName>, par exemple "MyClass.myFunction".

Dans le code de l'application, les fonctions de classes sont appelées comme des méthodes membres des instances d'objets et peuvent recevoir des paramètres si besoin. Les syntaxes suivantes sont prises en charge :

  • utilisation de l'opérateur (). Par exemple, myObject.methodName("hello")
  • utilisation d'une méthode membre de la classe "4D.Function" :
Attention thread-safety

Si une fonction de classe n'est pas thread-safe et qu'elle est appelée par une méthode ayant l'attribut "Peut être exécutée dans un process préemptif" :

  • le compilateur ne génère pas d'erreur (ce qui est différent par rapport aux méthodes standard),
  • une erreur est déclenchée par 4D uniquement au moment de l'exécution.

Paramètres

Les paramètres des fonctions sont déclarés via le nom du paramètre et son type, séparés par deux-points. Le nom du paramètre doit être conforme aux règles de nommage des propriétés. Les paramètres multiples (et leurs types) sont séparés par des points-virgules (;).

Function add($x; $y : Variant; $z : Integer; $xy : Object)
note

Si le type n'est pas fourni, le paramètre sera défini comme Variant.

Valeur retournée

Vous déclarez le paramètre de retour d'une fonction (optionnel) en ajoutant une flèche (->) et la définition du paramètre de retour après la liste des paramètres d'entrée, ou les deux points (:) et le type de paramètre de retour uniquement. Par exemple :

Function add($x : Variant; $y : Integer)->$result : Integer
$result:=$x+$y

Vous pouvez également déclarer le paramètre de retour en ajoutant seulement : type et utiliser l'expression return (elle mettra également fin à l'exécution de la fonction). Par exemple :

Function add($x : Variant; $y : Integer): Integer
// some code
return $x+$y

Exemple 1

property name : Text
property height; width : Integer

// Class: Rectangle
Class constructor($width : Integer; $height : Integer)
This.name:="Rectangle"
This.height:=$height
This.width:=$width

// Function definition
Function getArea()->$result : Integer
$result:=(This.height)*(This.width)
// Dans une méthode projet

var $rect : cs.Rectangle
var $area : Real

$rect:=cs.Rectangle.new(50;100)
$area:=$rect.getArea() //5000

Exemple 2

Cet exemple utilise l'expression return :

Function getRectArea($width : Integer; $height : Integer) : Integer
If ($width > 0 && $height > 0)
return $width * $height
Else
return 0
End if

Class Constructor

Syntaxe

// Class: MyClass
{shared} {{session} singleton} Class Constructor({$parameterName : type; ...})
// code
note

Il n'y a pas de mot-clé de fin pour le code d'une fonction de constructeur de classe. Le langage 4D détecte automatiquement la fin du code d'une fonction par le mot clé Function suivant ou la fin du fichier de classe.

Une fonction class constructor accepte des paramètres facultatifs et peut être utilisée pour créer et initialiser des objets de la classe utilisateur.

Lorsque vous appelez la fonction new(), le constructeur de classe est appelé avec les paramètres éventuellement passés à la fonction new().

Il ne peut y avoir qu'une seule fonction constructor dans une classe (sinon une erreur est renvoyée). La commande Super permet d'appeler la superclass, c'est-à-dire la classe mère de la fonction.

Vous pouvez créer et saisir des propriétés d'instance dans le constructeur (voir exemple). Alternativement, si les valeurs de vos propriétés d'instance ne dépendent pas des paramètres passés au constructeur, vous pouvez les définir en utilisant le mot-clé property.

L'utilisation du mot-clé shared crée une classe partagée, utilisée pour n'instancier que des objets partagés. Pour plus d'informations, reportez-vous au paragraphe Classes partagées.

Pour plus d'informations, référez-vous au paragraphe Classes singleton. L'utilisation du mot-clé singleton crée un singleton, utilisé pour créer une seule instance de la classe. Un singleton session crée une seule instance par session.

note

Les classes d'entités ORDA peuvent également bénéficier d'une fonction Class constructor. L'implémentation est similaire à celle des classes régulières mais avec quelques différences.

Exemple

// Class: MyClass
// Class constructor of MyClass
Class Constructor ($name : Text ; $age : Integer)
This.name:=$name
This.age:=$age
// Dans une méthode projet
// Vous pouvez instancier un objet
var $o : cs.MyClass
$o:=cs.MyClass.new("John";42)
// $o = {"name" : "John" ; "age":42}

property

Syntaxe

property <propertyName>{; <propertyName2>;...}{ : <propertyType>}

Le mot-clé property permet de déclarer une propriété à l'intérieur d'une classe utilisateur. Une propriété de classe a un nom et un type.

La déclaration des propriétés des classes améliore les suggestions de l'éditeur de code, les fonctions d'auto-complétion et la détection des erreurs.

Les propriétés sont déclarées pour les nouveaux objets lorsque vous appelez la fonction new(), mais elles ne sont pas automatiquement ajoutées aux objets (elles ne sont ajoutées que lorsqu'une valeur leur est assignée).

note

Une propriété est automatiquement ajoutée à l'objet lorsqu'elle est initialisée dans la ligne de déclaration.

Les noms des propriétés doivent être conformes aux règles de nommage des propriétés.

note

Étant donné que les propriétés et les fonctions partagent le même espace de nommage, il n'est pas permis d'utiliser le même nom pour une propriété et une fonction de la même classe (une erreur est générée dans ce cas).

Le type de propriété peut être l'un des suivants :

propertyTypeContenu
TextValeur texte
DateValeur date
TimeValeur Heure
BooleanValeur booléen
IntegerValeur entier long
RealValeur réel
PointerValeur pointeur
PictureValeur image
BlobValeur Blob scalaire
CollectionValeur collection
VariantValeur variant
ObjectObjet de classe par défaut (4D.Object)
4D.<className>Objet de la classe 4D className
cs.<className>Objet de la classe utilisateur className
cs.<namespace>.<className>Object de la classe className du composant <namespace>

Si vous omettez le type dans la ligne de déclaration, la propriété est créée en tant que variant.

info

Le mot-clé property ne peut être utilisé que dans les méthodes de classe et en dehors de tout bloc Function ou Class Constructor .

Initialisation de la propriété dans la ligne de déclaration

Lorsque vous déclarez une propriété, vous avez la flexibilité de spécifier son type de données et sa valeur dans une seule instruction. La syntaxe prise en charge est :

property <propertyName> { : <propertyType>} := <Propertyvalue>

note

Lorsque vous utilisez cette syntaxe, vous ne pouvez pas déclarer plusieurs propriétés dans la ligne de déclaration.

Vous pouvez omettre le type dans la ligne de déclaration, auquel cas le type sera déduit si possible. Par exemple :

// Class: MyClass

property name : Text := "Smith"
property age : Integer := 42

property birthDate := !1988-09-29! //date est déduit
property fuzzy //variant

Lorsque vous initialisez une propriété dans sa ligne de déclaration, elle est ajoutée à l'objet de classe après son instanciation avec la fonction new() mais avant que le constructeur ne soit appelé.

Si une classe étend une autre classe, les propriétés de la classe parente sont instanciées avant les propriétés de la classe enfant.

note

Si vous initialisez une propriété dans sa ligne de déclaration avec un objet ou une collection dans une classe partagée, la valeur est automatiquement transformée en une valeur partagée :

// dans une classe partagée
property myCollection := ["something"]
// myCollection sera une collection partagée
// équivalent à:
myCollection := New shared collection("something")

Exemple

// Class: MyClass

property name : Text
property age : Integer
property color : Text := "Blue"

Dans une méthode :

var $o : cs.MyClass
$o:=cs.MyClass.new() //$o:{"color" : "Blue"}
$o.name:="John" //$o:{"color" : "Blue"; "name" : "John"}
$o.age:="Smith" //erreur de syntaxe

Function get et Function set

Syntaxe

{local | server} {shared} Function get <name>()->$result : type
// code
{local | server} {shared} Function set <name>($parameterName : type)
// code

Function get et Function set sont des accesseurs définissant des propriétés calculées dans la classe. Une propriété calculée est une propriété nommée avec un type de données qui masque un calcul. Lorsqu'on accède à la valeur d'une propriété calculée, 4D substitue le code de l'accesseur correspondant :

  • lorsque la propriété est lue, Function get est exécutée,
  • lorsque la propriété est écrite, Function set est exécutée.

Si la propriété n'est pas accédée, le code n'est jamais exécuté.

note

Les classes d'entités ORDA bénéficient d'une implémentation étendue des propriétés calculées avec deux fonctions supplémentaires : query et orderBy.

Les propriétés calculées sont conçues pour gérer les données qui n'ont pas besoin d'être conservées en mémoire. Elles sont généralement basées sur des propriétés persistantes. Par exemple, si un objet de classe contient comme propriété persistante le prix brut et le taux de TVA, le prix net pourrait être traité par une propriété calculée.

Dans le fichier de définition de la classe, les déclarations de propriétés calculées utilisent les mots-clés Function get (le getter) et Function set (le setter), suivis du nom de la propriété. Le nom doit être conforme aux règles de nommage des propriétés.

Function get retourne une valeur du type de la propriété et Function set prend un paramètre du type de la propriété. Les deux arguments doivent être conformes aux paramètres de fonction standard.

Lorsque les deux fonctions sont définies, la propriété calculée est en lecture-écriture. Si seule une Function get est définie, la propriété calculée est en lecture seule. Dans ce cas, une erreur est retournée si le code tente de modifier la propriété. Dans ce cas, une erreur est retournée si le code tente de modifier la propriété.

Si une fonction définie à l'intérieur d'une classe partagée modifie les objets de la classe, elle devrait appeler la structure Use...End use pour protéger l'accès aux objets partagés. Pour plus d'informations, consultez le paragraphe sur les fonctions partagées ci-dessous.

Dans le contexte d'une application client/serveur, le mot-clé local ou server permet de spécifier sur quelle machine la fonction doit être exécutée. Ces mots-clés ne peuvent être utilisés qu'avec les fonctions du modèle de données ORDA et les fonctions singleton partagées/session. Pour plus d'informations, reportez-vous au paragraphe fonctions locales et serveur ci-dessous.

Le type de la propriété calculée est défini par la déclaration de type $return du getter. Il peut s'agir de n'importe quel type de propriété valide.

Assigner undefined à une propriété d'objet efface sa valeur tout en préservant son type. Pour ce faire, la Function get est d'abord appelée pour récupérer le type de valeur, puis Function set est appelée avec une valeur vide de ce type.

note

Les classes d'entités ORDA peuvent également bénéficier d'une fonction Class constructor. L'implémentation est similaire à celle des classes régulières mais avec quelques différences.

Exemple 1

//Class: Person.4dm
property firstName; lastName : Text

Class constructor($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname

Function get fullName() -> $fullName : Text
$fullName:=This.firstName+" "+This.lastName

Function set fullName( $fullName : Text )
$p:=Position(" "; $fullName)
This.firstName:=Substring($fullName; 1; $p-1)
This.lastName:=Substring($fullName; $p+1)
//dans une méthode projet
$fullName:=$person.fullName // Function get fullName() est appelée
$person.fullName:="John Smith" // Function set fullName() est appelée

Exemple 2

Function get fullAddress()->$result : Object

$result:=New object

$result.fullName:=This.fullName
$result.address:=This.address
$result.zipCode:=This.zipCode
$result.city:=This.city
$result.state:=This.state
$result.country:=This.country

Class extends <ClassName>

Syntaxe

// Class enfant
Class extends <ParentClass>

Le mot-clé Class extends est utilisé dans une déclaration de classe pour créer une classe utilisateur "enfant" d'une autre classe utilisateur. La classe "enfant" hérite de toutes les fonctions de la classe "parente".

L'extension de classe doit respecter les règles suivantes :

  • Une classe utilisateur ne peut pas étendre une classe intégrée (sauf 4D.Object et les classes ORDA qui sont étendues par défaut pour les classes utilisateur).
  • Une classe utilisateur ne peut pas étendre une classe utilisateur d'un autre projet ou composant.
  • Une classe utilisateur ne peut pas s'étendre elle-même.
  • Il n'est pas possible d'étendre des classes de manière circulaire (i.e. "a" étend "b" qui étend "a").
  • Il n'est pas possible de définir une classe utilisateur partagée à partir d'une classe utilisateur non partagée.

La violation de ces règles n'est pas détectable par l'éditeur de code ou l'interpréteur, seul le compilateur et la fonction vérifier syntaxe retourneront une erreur dans ce cas.

Une classe étendue peut appeler le constructeur de sa classe parente en utilisant la commande Super.

Exemple

Cet exemple crée une classe nommée Square à partir d'une classe nommée Polygon.

//Class: Square

//path: Classes/Square.4dm

Class extends Polygon

Class constructor ($side : Integer)

// Appelle le constructeur de la classe parente avec les longueurs
// fournies pour la largeur et la hauteur du Polygone
Super($side;$side)
// Dans les classes dérivées, Super doit être appelé
// avant que vous puissiez utiliser 'This'
This.name:="Square"



Function getArea() -> $area : Integer
$area:=This.height*This.width

Commandes de fonctions de classe

Les commandes suivantes ont des caractéristiques spécifiques lorsqu'elles sont utilisées dans les fonctions de classe :

Super

La commande Super permet d'appeler la superclass, c'est-à-dire la classe mère de la fonction. Il ne peut y avoir qu'une seule fonction constructor dans une classe (sinon une erreur est renvoyée).

Pour plus de détails, voir la description de la commande Super.

This

La commande This renvoie une référence à l'objet en cours de traitement. Dans la plupart des cas, la valeur de This est déterminée par la manière dont une fonction de classe est appelée. Habituellement, This fait référence à l'objet sur lequel la fonction a été appelée, comme si la fonction était sur l'objet.

Exemple :

//Classe : ob

Function f() : Integer
return This.a+This.b

Ensuite, vous pouvez écrire dans une méthode :

$o:=cs.ob.new()
$o.a:=5
$o.b:=3
$val:=$o.f() //8

Pour plus de détails, voir la description de la commande This.

OB Class

OB Class ( object ) -> Object | Null

OB Class retourne la classe de l'objet passé en paramètre.

OB Instance of

OB Instance of ( object ; class ) -> Boolean

OB Instance of retourne true si object appartient à la class ou à l'une de ses classes héritées, et false sinon.

Classes partagées

Vous pouvez créer des classes partagées. Une classe partagée est une classe utilisateur qui instancie un objet partagé lorsque la fonction new() est appelée dans la classe. Une classe partagée ne peut créer que des objets partagés.

Les classes partagées prennent également en charge les fonctions partagées qui peuvent être appelées sans Use...End use.

La propriété .isShared des objets Class permet de savoir si la classe est partagée.

info
  • Une classe héritant d'une classe non partagée ne peut pas être définie comme partagée.
  • Les classes partagées ne sont pas prises en charge par les classes basées sur ORDA.

Création d'une classe partagée

Pour créer une classe partagée, ajoutez le mot-clé shared avant le Class Constructor. Par exemple :

	//shared class: Person
shared Class Constructor($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname

//myMethod
var $person := cs.Person.new("John"; "Smith")
OB Is shared($person) // true
cs.Person.isShared //true

Fonctions partagées

Si les fonctions sont déclarées dans une classe partagée, vous pouvez utiliser le mot-clé shared avec elles afin qu'elles puissent être appelées sans la structure Use...End use. Pour plus d'informations, consultez le paragraphe sur les fonctions partagées ci-dessous.

Pour créer une fonction partagée, ajoutez le mot-clé shared avant le mot-clé Function dans une classe partagée. Par exemple :

	//classe partagée Foo
shared Class Constructor()
This.variable:=1

shared Function Bar($value : Integer)
This.variable:=$value //pas besoin de use/end use
note

Si le mot-clé shared est utilisé devant une fonction dans une classe utilisateur non partagée, il est ignoré.

Classes Singleton

Une classe singleton est une classe utilisateur qui ne produit qu'une seule instance. Pour plus d’informations sur le concept de singleton, veuillez consulter la page Wikipédia sur les singletons.

Types de singletons

Les singletons sont utiles pour définir des valeurs qui doivent être disponibles partout dans une application, une session ou un process.

4D prend en charge trois types de singletons :

  • un singleton process a une instance unique pour le process dans lequel il est instancié,
  • un singleton partagé a une instance unique pour tous les process sur la machine.
  • un singleton session est un singleton partagé, mais avec une instance unique pour tous les process de la session. Les singletons de session sont partagés au sein d'une même session mais varient d'une session à l'autre. Dans le contexte d'une application client-serveur ou web, les singletons de session permettent de créer et d'utiliser une instance différente pour chaque session, et donc pour chaque utilisateur. Les singletons de session sont particulièrement appropriés pour les applications Qodly.
info

Les classes Singleton ne sont pas prises en charge par les classes ORDA.

Le tableau suivant indique la portée d'une instance de singleton en fonction de l'endroit où elle a été créée :

Singleton créé surPortée d'un singleton processPortée d'un singleton partagéPortée d'un singleton session
4D mono-utilisateurProcessApplicationApplication ou session Web/REST
4D ServerProcessMachine 4D ServerSession client/serveur ou session Web/REST ou session de procédure stockée
4D mode distantProcess (note: les singletons ne sont pas synchronisés sur les process jumeaux)Machine 4D distantMachine distante 4D ou session Web/REST

Une fois instanciée, une classe singleton (et son singleton) existe aussi longtemps qu'une référence à cette classe existe quelque part dans l'application sur le poste.

Création et utilisation de singletons

Vous déclarez des classes singleton en ajoutant le(s) mot(s) clé(s) approprié(s) devant le Class constructor :

  • Pour déclarer une classe singleton process, écrivez singleton Class Constructor().
  • Pour déclarer une classe singleton partagée, écrivez shared singleton Class constructor().
  • Pour déclarer une classe singleton de session, écrivez session singleton Class constructor().
note
  • Les singletons de session sont automatiquement des singletons partagés (il n'est pas nécessaire d'utiliser le mot-clé shared dans le constructeur de la classe).
  • Les fonctions de singletons partagés prennent en charge le mot-clé onHTTPGet.

Le singleton de la classe est instancié au premier appel de la fonction cs.<class>.me propriété. Le singleton instancié de la classe est ensuite toujours renvoyé lorsque la propriété me est utilisée.

Si vous avez besoin d'instancier un singleton avec des paramètres, vous pouvez également appeler la fonction new(). Dans ce cas, il est recommandé d'instancier le singleton dans du code exécuté au démarrage de l'application.

La propriété .isSingleton des objets de classe permet de savoir si la classe est un singleton.

La propriété .isSessionSingleton des objets de classe permet de savoir si la classe est un singleton de session.

Fonctions singleton exposées

Les fonctions singleton partagées et de session prennent en charge le mot-clé exposed. Une fonction singleton exposée peut être directement appelée par des requêtes REST. Cette fonctionnalié est utile pour la conception de pages Qodly appelant des fonctions 4D.

Exemples

Singleton process

	//class: ProcessTag
singleton Class Constructor()
This.tag:=Random

Pour utiliser le singleton :

	//dans un process
var $mySingleton := cs.ProcessTag.me //Première instanciation
//$mySingleton.tag = 5425 par exemple
...
var $myOtherSingleton := cs.ProcessTag.me
//$myOtherSingleton.tag = 5425

	//dans un autre process
var $mySingleton := cs.ProcessTag.me //Première instanciation
//$mySingleton.tag = 14856 par exemple
...
var $myOtherSingleton := cs.ProcessTag.me
//$myOtherSingleton.tag = 14856

Singleton partagé

//Class VehicleFactory

property vehicleBuilt : Integer

shared singleton Class constructor()
This.vehicleBuilt := 0 //Nombre de véhiclues produits par l'usine

shared Function buildVehicle ($type : Text) -> $vehicle : cs.Vehicle

Case of
: $type="car"
$vehicle:=cs.Car.new()
: $type="truck"
$vehicle:=cs.Truck.new()
: $type="sport car"
$vehicle:=cs.SportCar.new()
: $type="motorbike"
$vehicle:=cs.Motorbike.new()
Else
$vehicle:=cs.Car.new()
End case
This.vehicleBuilt+=1

Vous pouvez alors appeler le singleton cs.VehicleFactory pour obtenir un nouveau véhicule depuis n'importe où dans votre application sur le poste avec une seule ligne :

$vehicle:=cs.VehicleFactory.me.buildVehicle("truck")

Étant donné que la fonction buildVehicle() modifie le singleton cs.VehicleFactory (en incrémentant This.vehicleBuilt), vous devez ajouter le mot-clé shared à celle-ci.

Singleton session

Dans une application d'inventaire, vous souhaitez mettre en œuvre un inventaire d'articles à l'aide de singletons de session.

//class ItemInventory

property itemList : Collection:=[]

session singleton Class constructor()

shared function addItem($item:object)
This.itemList.push($item)

En définissant la classe ItemInventory comme un singleton de session, vous vous assurez que chaque session, et donc chaque utilisateur, dispose de son propre inventaire. Pour accéder à l'inventaire de l'utilisateur, rien de plus simple :

//dans une session utilisateur
$myList := cs.ItemInventory.me.itemList
//liste d'objets de l'utilisateur courant

local et server

Dans l'architecture client/serveur, les mots-clés local et server vous permettent de spécifier où vous voulez que la fonction soit exécutée : côté client ou côté serveur. Le contrôle de l'emplacement d'exécution est utile pour des raisons de performance ou pour la mise en de fonctions métier logiques.

La syntaxe formelle est la suivante :

// déclarer une fonction à exécuter sur un client dans le cadre du client/serveur
local Function <functionName>
// déclarer une fonction à exécuter sur le serveur en client/serveur
server Function <functionName>

Les mots-clés local et server ne sont disponibles que pour les fonctions des classes suivantes :

Vue d’ensemble

Les fonctions prises en charge ont un emplacement d'exécution par défaut lorsqu'aucun mot-clé d'emplacement n'est utilisé. Vous pouvez néanmoins insérer un mot-clé local ou server pour modifier le lieu d'exécution, ou pour rendre le code plus explicite.

Fonctions prises en chargeExécution par défautavec le mot-clé localavec le mot-clé server
Modèle de données ORDAsur le serveurLa fonction est exécutée sur le client si elle est appelée sur le client
Singleton partagé ou de sessionLocalLa fonction est exécutée sur le serveur sur l'instance serveur du singleton.
S'il n'y a aucune instance du singleton sur le serveur, elle est créée.

Si les mots-clés local et server sont utilisés dans un autre contexte, une erreur est retournée.

note

Pour une description globale des emplacements où le code est réellement exécuté en client/serveur, veuillez vous référer à cette section.

local

Dans l'[architecture client/serveur] (../Desktop/clientServer.md), le mot-clé local spécifie que la fonction doit être exécutée sur la machine à partir de laquelle elle est appelée.

Rappel

Le mot-clé local est inutile pour les fonctions singleton partagées ou de session, qui sont exécutées localement par défaut.

Par défaut, les fonctions du modèle de données ORDA sont exécutées sur le serveur. Cela garantit généralement les meilleures performances puisque seuls la requête de fonction et le résultat sont envoyés sur le réseau. Cependant, pour des raisons d'optimisation, vous pouvez vouloir exécuter une fonction de modèle de données sur le client. Vous pouvez alors utiliser le mot clé local.

Exemple: Calcul de l'âge

Considérons une entité avec un attribut birthDate. Nous souhaitons définir une fonction age() qui serait appelée dans une list box. Cette fonction peut être exécutée sur le client, ce qui évite de déclencher une requête au serveur pour chaque ligne de la list box.

Dans la classe StudentsEntity :

Class extends Entity

local Function age() -> $age: Variant

If (This.birthDate#!00-00-00!)
$age:=Year of(Current date)-Year of(This.birthDate)
Else
$age:=Null
End if

server

Dans l'architecture client/serveur, le mot-clé server spécifie que la fonction doit être exécutée sur le serveur.

Rappel

Le mot clé server est inutile avec les fonctions du modèle de données ORDA, qui sont exécutées sur le serveur par défaut.

Les paramètres et le résultat de la fonction server doivent être streamable. Par exemple, 4D.Datastore, File handle, ou WebServer sont des classes non streamables mais 4D.File est streamable.

Cette fonctionnalité est particulièrement utile dans le cadre des [sessions utilisateur à distance](../Desktop/sessions.md# remote-user-sessions), vous permettant d'implémenter la logique métier dans un singleton de session afin de la partager entre tous les processus de la session, étendant ainsi les fonctionnalités de la commande Session. Dans ce cas, vous pourrez vouloir que la logique applicative soit exécutée sur le serveur afin que toutes les informations relatives à la session soient rassemblées sur le serveur.

Par défaut, les fonctions singleton partagées ou de session sont exécutées localement. L'ajout du mot-clé server dans la définition de la fonction de la classe permet à 4D d'utiliser l'instance singleton sur le serveur. Notez que cela peut entraîner l'instanciation du singleton sur le serveur s'il n'existe pas encore d'instance.

Pour les sessions singleton, la fonction est exécutée sur le serveur dans l'instance de singleton correspondante, c'est-à-dire l'instance de singleton pour la session courante.

note

Si vous déclarez une server Function dans un singleton partagé puis :

  • vous instanciez un singleton S1 sur le client (nommé s1),
  • vous exécutez s1.function() sur le client.

Si aucune instance de S1 n'existe sur le serveur à ce moment-là, S1 est instancié sur le serveur (le constructeur est exécuté) et function() s'exécute sur cette instance de serveur. Par conséquent, deux instances de S1 peuvent coexister (côté client et côté serveur), avec des valeurs de propriété distinctes. Dans ce cas, s1.property est toujours accessible localement. Il n'est pas possible d'y accéder sur le serveur, par exemple à partir de code côté serveur utilisant la notation à point directe (une erreur est renvoyée).

Exemple : singleton Administration

Le singleton partagé Administration possède une fonction "server" qui exécute la commande Process activity. Ce singleton est instancié sur un 4D distant mais la fonction renvoie l'activité du serveur sur le serveur.

  // Administration class

shared singleton Class constructor

// Cette fonction est exécutée sur le serveur
server Function processActivity() : Object
return Process activity


Function localProcessActivity() : Object
return Process activity

Code s'exécutant sur le client :

var $localActivity; $serverActivity : Object
var $administration : cs.Administration

// Le singleton Administration est instancié sur le client 4D
$administration:=cs.Administration.me

// Obtenir les process en cours d'exécution sur le serveur 4D distant
$localActivity:=$administration.localProcessActivity()

// Obtenir les process et les sessions en cours d'exécution sur le serveur 4D
$serverActivity:=$administration.processActivity()

Exemple: singleton de session

Vous stockez vos utilisateurs dans une table Users et vous gérez une authentification personnalisée. Vous utilisez un singleton de session pour l'authentification :

// Classe singleton session UserSession

server Function checkUser($credentials : Object) : Boolean

var $user : cs.UsersEntity
var $result:=False

If ($credentials#Null)
$user:=ds.Users.query("Email === :1"; $credentials.identifier).first()

If (($user#Null) && (Verify password hash($credentials.password; $user.Password)))
Use (Session.storage)
Session.storage.userInfo:=New shared object("userId"; $user.ID)
End use

$result:=True
End if
End if

return $result

Pour fournir l'utilisateur courant aux clients 4D, le singleton expose une propriété calculée de l'utilisateur obtenue du serveur :

server Function get user() : cs.UsersEntity
return ds.Users.get(Session.storage.userInfo.userId)