Clases
Generalidades
El lenguaje 4D soporta el concepto de clases. En un lenguaje de programación, el uso de una clase permite definir el comportamiento de un objeto con propiedades y funciones asociadas.
Una vez definida una clase usuario, puede instanciar los objetos de esta clase en cualquier parte de su código. Una vez definida una clase usuario, puede instanciar los objetos de esta clase en cualquier parte de su código. Una clase puede extend otra clase, y luego hereda sus funciones y propiedades (declaradas y calculadas).
El modelo de clases en 4D es similar al de las clases en JavaScript, y se basa en una cadena de prototipos.
Por ejemplo, puede crear una clase Person con la siguiente definición:
//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
En un método, creando una "Persona":
var $person : cs.Person //object of Person class
var $hello : Text
$person:=cs.Person.new("John";"Doe")
// $person:{firstName: "John"; lastName: "Doe"; fullName: "John Doe"}
$hello:=$person.sayHello() //"Hello John Doe"
Class files are managed through the 4D Explorer (see Creating classes).
Borrar una clase
To delete an existing class, select it in the Explorer and click or choose Move to Trash from the contextual menu.
You can also remove the .4dm class file from the "Classes" folder on your disk.
Class stores
Las clases disponibles son accesibles desde sus class stores. Hay dos class stores disponibles:
cs
cs : Object
| Parámetros | Tipo | Descripción | |
|---|---|---|---|
| classStore | Object | ← | Class store usuario para el proyecto o componente |
El comando cs devuelve el almacén de clases de usuario para el proyecto o componente actual. Devuelve todas las clases de usuario definidas en el proyecto o componente abierto. Por defecto, sólo las clases ORDA están disponibles.
Ejemplo
Quiere crear una nueva instancia de un objeto de myClass:
$instance:=cs.myClass.new()
4D
4D : Object
| Parámetros | Tipo | Descripción | |
|---|---|---|---|
| classStore | Object | ← | Class store 4D |
El comando 4D devuelve el almacén de clases para las clases 4D integradas. Ofrece acceso a las APIs específicas como CryptoKey.
Ejemplos
Quiere crear una nueva llave en la clase CryptoKey:
$key:=4D.CryptoKey.new(New object("type";"ECDSA";"curve";"prime256v1"))
Quiere listar las clases integradas en 4D:
var $keys : Collection
$keys:=OB Keys(4D)
ALERT("There are "+String($keys.length)+" built-in classes.")
El objeto clase
Cuando una clase es definida en el proyecto, se carga en el entorno del lenguaje 4D. Una clase es un objeto de la clase "Class". Un objeto clase tiene las siguientes propiedades y funciones:
- cadena
name - objeto
superclass(null si no hay) - función
new(), que permite instanciar objetos de clase - propiedad
isShared, true si la clase es compartida - propiedad
isSingleton, verdadero si la clase define una clase singleton. - propiedad
isSectionSingleton, true si la clase define un sesión singleton. - Propiedad
me, que permite instanciar y acceder a singletons.
Además, un objeto clase puede hacer referencia a un objeto constructor (opcional).
Un objeto de clase en sí mismo es un objeto compartido y, por tanto, se puede acceder a él desde diferentes procesos de 4D simultáneamente.
Herencia
Si una clase hereda de otra clase (es decir, se utiliza la palabra clave Class extends en su definición), la clase padre es su superclass.
Cuando 4D no encuentra una función o una propiedad en una clase, la busca en su superclass; si no la encuentra, 4D sigue buscando en la superclase de la superclase, y así sucesivamente hasta que no haya más superclase (todos los objetos heredan de la superclase "Object").
Palabras clave de clase
En las definiciones de clase se pueden utilizar palabras claves específicas de 4D:
Function <Name>para definir las funciones de clase de los objetos.Class constructorpara inicializar nuevos objetos de la clase.propertypara definir propiedades estáticas de los objetos con un tipo.Function get <Name>yFunction set <Name>para definir las propiedades calculadas de los objetos.Class extends <ClassName>para definir la herencia.ThisySuperson comandos que tienen funcionalidades especiales dentro de clases.
Function
Sintaxis
{local | server} {shared} Function <name>({$parameterName : type; ...}){->$parameterName : type}
// code
No hay palabra clave final para el código de una función. El lenguaje 4D detecta automáticamente el final del código de una función por la siguiente palabra clave Function o el final del archivo de clase.
Las funciones de clase son propiedades específicas de la clase. Son objetos de la clase 4D.Function. En el archivo de definición de clase, las declaraciones de función utilizan la palabra clave Function seguida del nombre de la función.
Si las funciones se declaran en una clase compartida, puede utilizar la palabra clave shared con ellas para que puedan ser llamadas sin la estructura Use...End use. Para obtener más información, consulte el párrafo Funciones compartidas a continuación.
In the context of a client/server application, the local or server keyword allows you to specify on which machine the function must be executed. These keywords can only be used with ORDA data model functions and shared/session singleton functions. For more information, refer to the local and server functions paragraph below.
El nombre de la función debe ser compatible con las reglas de nomenclatura de objetos.
Dado que las propiedades y las funciones comparten el mismo espacio de nombres, no está permitido utilizar el mismo nombre para una propiedad y una función de la misma clase (en este caso se produce un error).
Comenzar el nombre de la función con un caracter guión bajo ("_") excluirá la función de las funcionalidades de autocompletado en el editor de código 4D. Por ejemplo, si declara Function _myPrivateFunction en MyClass, no se propondrá en el editor de código cuando digite en "cs.MyClass. ".
Inmediatamente después del nombre de la función, los parámetros de la función se pueden declarar con un nombre y un tipo de datos asignados, incluido el parámetro de retorno (opcional). Por ejemplo:
Function computeArea($width : Integer; $height : Integer)->$area : Integer
En una función de clase, el comando This se utiliza como instancia del objeto. Por ejemplo:
Function setFullname($firstname : Text; $lastname : Text)
This.firstName:=$firstname
This.lastName:=$lastname
Function getFullname()->$fullname : Text
$fullname:=This.firstName+" "+Uppercase(This.lastName)
Para una función clase, el comando Current method name devuelve: <ClassName>.<FunctionName>, por ejemplo "MyClass.myFunction".
En el código de la aplicación, las funciones de clases se llaman como los métodos miembros de las instancias de objetos y pueden recibir parámetros si los hay. Se soportan las siguientes sintaxis:
- uso del operador
(). Por ejemplo,myObject.methodName("hello") - utilización de un método miembro de la clase "4D.Function":
Si una función de clase no es hilo seguro y es llamada por un método con el atributo "Puede ejecutarse en proceso apropiativo":
- el compilador no genera ningún error (lo que es diferente en comparación con los métodos regulares),
- un error es lanzado por 4D sólo en tiempo de ejecución.
Parámetros
Los parámetros de las funciones se declaran utilizando el nombre del parámetro y su tipo, separados por dos puntos. El nombre del parámetro debe cumplir con las reglas de nomenclatura de las propiedades. Múltiples parámetros (y tipos) están separados por punto y coma (;).
Function add($x; $y : Variant; $z : Integer; $xy : Object)
Si no se declaró el tipo, el parámetro se definirá como Variant.
Valor devuelto
Se declara el parámetro de retorno (opcional) añadiendo una flecha (->) y la definición del parámetro de retorno después de la lista de parámetros de entrada, o dos puntos (:) y el tipo de parámetro de retorno únicamente. Por ejemplo:
Function add($x : Variant; $y : Integer)->$result : Integer
$result:=$x+$y
También puedes declarar el parámetro de retorno añadiendo sólo : type y utilizar la expresión return (también terminará la ejecución de la función). Por ejemplo:
Function add($x : Variant; $y : Integer): Integer
// algo de código
return $x+$y
Ejemplo 1
property name : Text
property height; width : Integer
// Clase: Rectangle
Class constructor($width : Integer; $height : Integer)
This.name:="Rectangle"
This.height:=$height
This.width:=$width
// Definición de función
Function getArea()->$result : Integer
$result:=(This.height)*(This.width)
// En un método proyecto
var $rect : cs.Rectangle
var $area : Real
$rect:=cs.Rectangle.new(50;100)
$area:=$rect.getArea() //5000
Ejemplo 2
Este ejemplo utiliza la expresión return:
Function getRectArea($width : Integer; $height : Integer) : Integer
If ($width > 0 && $height > 0)
return $width * $height
Else
return 0
End if
Class constructor
Sintaxis
// Class: MyClass
{shared} {{session} singleton} Class constructor({$parameterName : type; ...})
// código
No hay palabra clave final para el código de función class constructor. El lenguaje 4D detecta automáticamente el final del código de una función por la siguiente palabra clave Function o el final del archivo de clase.
Una función constructora de clase acepta parámetros opcionales y puede ser utilizada para crear e inicializar objetos de la clase del usuario.
Cuando llama a la función new(), el constructor de clase es llamado con los parámetros opcionalmente pasados a la función new().
Sólo puede haber una función constructora en una clase (de lo contrario se devuelve un error). El comando Super permite realizar llamadas a superclass, es decir, a la clase padre de la función.
Puede crear y escribir propiedades de instancia dentro del constructor (ver ejemplo). Alternativamente, si los valores de las propiedades de instancia no dependen de los parámetros pasados al constructor, puede definirlos utilizando la palabra clave property.
Utilizando la palabra clave shared se crea una clase compartida, utilizada para instanciar únicamente objetos compartidos. Para obtener más información, consulte el párrafo Clases compartidas.
Utilizando la palabra clave singleton se crea un singleton, utilizado para crear una sola instancia de la sesión. Un session singleton crea una sola instancia por sesión. Para obtener más información, consulte el párrafo Clases singleton.
Las clases de entidad ORDA también pueden beneficiarse de una función Class constructor. La implementación es similar a la de las clases normales pero con algunas diferencias.
Ejemplo
// Class: MyClass
// Class constructor of MyClass
Class constructor ($name : Text ; $age : Integer)
This.name:=$name
This.age:=$age
// En un método proyecto
// Se puede instanciar un objeto
var $o : cs.MyClass
$o:=cs.MyClass.new("John";42)
// $o = {"name":"John";"age":42}
propiedad
Sintaxis
property <propertyName>{; <propertyName2>;...}{ : <propertyType>}
La palabra claveproperty se puede utilizar para declarar una propiedad dentro de una clase usuario. Una propiedad de clase tiene un nombre y un tipo.
La declaración de propiedades de clase mejora las sugerencias del editor de código, las funciones de tecleo predictivo y la detección de errores.
Las propiedades se declaran para nuevos objetos cuando llama a new(), sin embargo, no se añaden automáticamente a los objetos (sólo se añaden cuando se les asigna un valor).
Una propiedad se añade automáticamente al objeto cuando se inicializa en la línea de declaración.
Los nombres de las propiedades deben cumplir las normas de denominación de propiedades.
Dado que las propiedades y las funciones comparten el mismo espacio de nombres, no está permitido utilizar el mismo nombre para una propiedad y una función de la misma clase (en este caso se produce un error).
El tipo de propiedad puede ser uno de los siguientes tipos soportados:
| propertyType | Contenido |
|---|---|
Text | Valor texto |
Date | Valor fecha |
Time | Valor Hora |
Boolean | Valor booleano |
Integer | Valor entero largo |
Real | Valor real |
Pointer | Valor puntero |
Picture | Valor imagen |
Blob | Valeor Blob escalar |
Collection | Valor colección |
Variant | Valor variant |
Object | Objeto con clase por defecto (4D.object) |
4D.<className> | Objeto del nombre de la clase 4D |
cs.<className> | Objeto del nombre de la clase usuario |
cs.<namespace>.<className> | Objeto del componente <namespace> nombre de la clase |
Si omite el tipo en la línea de declaración, la propiedad se crea como una variante.
La palabra clave property sólo puede utilizarse en métodos clase y fuera de cualquier bloque Function o Class constructor.
Inicialización de la propiedad en la línea de declaración
Al declarar una propiedad, tiene la flexibilidad de especificar su tipo de datos y proporcionar su valor en una sola declaración. La sintaxis soportada es:
property <propertyName> { : <propertyType>} := <Propertyvalue>
Cuando se utiliza esta sintaxis, no se pueden declarar varias propiedades en la línea de declaración.
Puede omitir el tipo en la línea de declaración, en cuyo caso el tipo se deducirá cuando sea posible. Por ejemplo:
// Class: MyClass
property name : Text := "Smith"
property age : Integer := 42
property birthDate := !1988-09-29! //se deduce la fecha
property fuzzy //variant
Cuando inicializa una propiedad en su línea de declaración, se agrega al objeto de la clase después de su instanciación con la función new() pero antes de llamar al constructor.
Si una clase extiende a otra, las propiedades de la clase padre se instancian antes que las propiedades de la clase hija.
Si inicializa una propiedad en su línea de declaración con un objeto o una colección en una clase compartida, el valor se transforma automáticamente en un valor compartido:
// en una clase compartida
property myCollection := ["something"]
// myCollection será una colección compartida
// equivalente a:
myCollection := New shared collection("something")
Ejemplo
// Clase: MyClass
property name : Text
property age : Integer
property color : Text := "Blue"
En un método:
var $o : cs.MyClass
$o:=cs.MyClass.new() //$o:{"color" : "Blue"}
$o.name:="Juan" //$o:{"color" : "Azul"; "name" : "John"}
$o.age:="Smith" //error con la sintaxis de verificación
Function get y Function set
Sintaxis
{local | server} {shared} Function get <name>()->$result : type
// code
{local | server} {shared} Function set <name>($parameterName : type)
// code
Function get y Function set son accesos que definen las propiedades calculadas en la clase. Una propiedad calculada es una propiedad nombradas con un tipo de datos que enmascara un cálculo. Cuando se accede a un valor de propiedad calculado, 4D sustituye el código del accesor correspondiente:
- cuando se lee la propiedad,
Function getse ejecuta, - cuando se escribe la propiedad,
Function getse ejecuta.
Si no se accede a la propiedad, el código nunca se ejecuta.
Las clases de entidad ORDA se benefician de una implementación extendida de propiedades computadas con dos funciones adicionales: query y orderBy.
Las propiedades calculadas están diseñadas para manejar datos que no necesitan ser guardados en memoria. Generalmente se basan en propiedades persistentes. Por ejemplo, si un objeto de clase contiene como propiedad persistente el precio bruto y el tipo de IVA, El precio neto podría ser manejado por una propiedad calculada.
En el archivo de definición de la clase, las declaraciones de propiedades calculadas utilizan las palabras claves Function get (getter) y Function set (setter) seguido por el nombre de la propiedad. El nombre debe cumplir con las reglas de nomenclatura de las propiedades.
Función get devuelve un valor del tipo de la propiedad y Function set toma un parámetro del tipo de la propiedad. Ambos argumentos deben cumplir con los parámetros de función estándar.
Cuando ambas funciones están definidas, la propiedad calculada es read-write. Si solo se define una Function get, la propiedad calculada es de solo lectura. En este caso, se devuelve un error si el código intenta modificar la propiedad. En este caso, se devuelve un error si el código intenta modificar la propiedad.
Si las funciones se declaran en una clase compartida, puede utilizar la palabra clave shared con ellas para que puedan ser llamadas sin la estructura Use...End use. Para obtener más información, consulte el párrafo Funciones compartidas a continuación.
In the context of a client/server application, the local or server keyword allows you to specify on which machine the function must be executed. These keywords can only be used with ORDA data model functions and shared/session singleton functions. For more information, refer to the local and server functions paragraph below.
El tipo de la propiedad calculada es definido por la declaración de tipo $return del *getter *. Puede ser de cualquier tipo de propiedad válido.
Asignar undefined a una propiedad de objeto limpia su valor mientras se preserva su tipo. Para ello, la
Function getes llamada primero para recuperar el tipo de valor, luegoFunction setes llamado con un valor vacío de ese tipo.
Las clases de entidad ORDA también pueden beneficiarse de una función Class constructor. La implementación es similar a la de las clases normales pero con algunas diferencias.
Ejemplo 1
//Clase: 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)
//en un método proyecto
$fullName:=$person.fullName // Function get fullName() is called
$person.fullName:="John Smith" // Function set fullName() is called
Ejemplo 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>
Sintaxis
// Class hijo
Class extends <ParentClass>
La palabra clave Class extends se utiliza en la declaración de clase para crear una clase usuario que es hijo de otra clase usuario. La clase hijo hereda todas las funciones de la clase padre.
La extensión de clase debe respetar las siguientes reglas:
- Una clase de usuario no puede extender una clase integrada (excepto las 4D.Object y clases ORDA que se extienden por defecto para las clases de usuario).
- Una clase usuario no puede extender una clase usuario de otro proyecto o componente.
- Una clase usuario no puede extenderse a sí misma.
- No es posible extender las clases de una manera circular (es decir, "a" extiende "b" que extiende "a").
- No es posible definir una clase usuario compartida extendida a partir de una clase usuario no compartida.
La ruptura de tal regla no es detectada por el editor de código o el intérprete, solo el compilador y comprobar sintaxis arrojará un error en este caso.
Una clase extendida puede llamar al constructor de su clase padre utilizando el comando Super.
Ejemplo
Este ejemplo crea una clase llamada Square de una clase llamada Polygon.
//Clase: Square
//ruta: Classes/Square.4dm
Class extends Polygon
Class constructor ($side : Integer)
Llama al constructor de la clase padre con las longitudes
// suministradas para el ancho y alto del polígono
Super($side;$side)
// En las clases derivadas, Super debe ser llamado antes de
// utilizar 'This'
This.name:="Square"
Function getArea() -> $area : Integer
$area:=This.height*This.width
Comandos de función clase
Los siguientes comandos tienen características específicas cuando se utilizan dentro de las funciones clase:
Super
El comando Super permite realizar llamadas a superclass, es decir, a la clase padre de la función. Sólo puede haber una función constructora en una clase (de lo contrario se devuelve un error).
Para más detalles, vea la descripción del comando Super.
This
El comando This devuelve una referencia al objeto procesado actualmente. En la mayoría de los casos, el valor de This está determinado por cómo se llama una función clase. Normalmente, This se refiere al objeto al que la función fue llamada, como si la función estuviera sobre el objeto.
Ejemplo:
//Clase: ob
Function f() : Integer
return This.a+This.b
A continuación, puede escribir en un método:
$o:=cs.ob.new()
$o.a:=5
$o.b:=3
$val:=$o.f() //8
Para más detalles, vea la descripción del comando This.
OB Class
OB Class ( object ) -> Object | Null
OB Class devuelve la clase del objeto pasado como parámetro.
OB Instance of
OB Instance of ( object ; class ) -> Boolean
OB Instance of devuelve true si object pertenece a la class o a una de las clases heredadas y false de lo contrario.
Clases compartidas
Puede crear clases compartidas. Una clase compartida es una clase usuario que instancia un objeto compartido cuando se llama a la función new() en la clase. Una clase compartida sólo puede crear objetos compartidos.
Las clases compartidas también admiten funciones compartidas que pueden llamarse sin estructuras Use...End use.
La propiedad .isShared de los objetos de la Clase permite saber si la clase está compartida.
- Una clase que hereda de una clase no compartida no puede definirse como compartida.
- Las clases compartidas no están soportadas por las clases basadas en ORDA.
Creación de una clase compartida
Para crear una clase compartida, añada la palabra clave shared antes del Class constructor. Por ejemplo:
//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
Funciones compartidas
Si una función definida al interior de una clase compartida modifica objetos de la clase, debería llamar a la estructura Use...End use para proteger el acceso a los objetos compartidos. Sin embargo, para simplificar el código, puede definir la función como compartida, de modo que active automáticamente un Use...End use interno cuando se ejecute.
Para crear una función compartida, añada la palabra clave shared antes de la palabra clave Function en una clase compartida. Por ejemplo:
//clase compartida Foo
shared Class constructor()
This.variable:=1
shared Function Bar($value : Integer)
This.variable:=$value //no es necesario llamar use/end use
Si se utiliza la palabra clave shared en una clase usuario no compartida, se ignora.
Clases Singleton
Una clase singleton es una clase usuario que sólo produce una única instancia. Para más información sobre el concepto de singletons, por favor consulte la página Wikipedia sobre los singletons.
Tipos de Singletons
Los singletons son útiles para definir los valores que necesitan estar disponibles desde cualquier parte de una aplicación, una sesión o un proceso.
4D soporta tres tipos de singletons:
- un singleton proceso tiene una instancia única para el proceso en el que se instancia,
- un singleton compartido tiene una instancia única para todos los procesos en la máquina.
- un singleton de sesión es un singleton compartido pero con una instancia única para todos los procesos en la sesión. Los singletons de sesión son compartidos dentro de una sesión completa, pero varían entre sesiones. En el contexto de un cliente-servidor o una aplicación web, los singletons de sesión hacen posible crear y utilizar una instancia diferente para cada sesión, y por lo tanto para cada usuario. Los singletons de sesión son particularmente apropiados con aplicaciones Qodly.
Las clases Singleton no están soportadas por las clases ORDA.
La siguiente tabla indica el alcance de una instancia singleton dependiendo de donde se creó:
| Singleton creado en | Alcance del proceso singleton | Alcance del singleton compartido | Alcance del singleton de sesión |
|---|---|---|---|
| 4D monopuesto | Proceso | Aplicación | Aplicación o sesión Web/REST |
| 4D Server | Proceso | Máquina 4D Server | Sesión cliente/servidor o sesión Web/REST o sesión de procedimiento almacenado |
| Modo remoto 4D | Proceso (nota: los singletons no están sincronizados en el proceso gemelo) | Máquina remota 4D | Máquina remota 4D o sesión Web/REST |
Una vez instanciado, existe una clase singleton (y su singleton) siempre que exista una referencia a ella en algún lugar de la aplicación que se ejecuta en la máquina.
Crear y utilizar singletons
Se declaran clases singleton añadiendo la(s) palabra(s) clave(s) apropiada(s) antes del Class constructor:
- Para declarar una clase singleton (proceso), escriba
singleton Class constructor(). - Para declarar una clase singleton compartida, escribe
shared singleton Class constructor(). - Para declarar una clase singleton de sesión, escriba
session singleton Class constructor().
- Los singletons de sesión son automáticamente singletons compartidos (no hay necesidad de usar la palabra clave
shareden el constructor de clases). - Las funciones compartidas Singleton soportan palabra clave
onHTTPGet.
La clase singleton está instanciada en la primera llamada de la propiedad cs.<class>.me. El singleton instanciado de la clase se devuelve siempre cuando se utiliza la propiedad me.
Si necesita instanciar un singleton con parámetros, también puede llamar la función new(). En este caso, se recomienda instanciar el singleton en algún código ejecutado al inicio de la aplicación.
La propiedad isSingleton de los objetos Clase permite saber si la clase es un singleton.
La propiedad .isSessionSingleton de los objetos Class permite saber si la clase es un singleton de sesión.
Funciones singleton expuestas
Las funciones singleton compartidas y de sesión soportan la palabra clave exposed. Una función singleton expuesta puede ser llamada directamente por peticiones REST. Esta función es útil para diseñar páginas Qodly que llamen a las funciones 4D.
Ejemplos
Singleton Proceso
//class: ProcessTag
singleton Class constructor()
This.tag:=Random
Para utilizar el singleton:
//en otro proceso
var $mySingleton := cs.ProcessTag.me //Primera instanciación
//$mySingleton.tag = 5425 por ejemplo
...
var $myOtherSingleton := cs.ProcessTag.me
//$myOtherSingleton.tag = 5425
//en otro proceso
var $mySingleton := cs.ProcessTag.me //Primera instanciación
//$mySingleton.tag = 14856 por ejemplo
...
var $myOtherSingleton := cs.ProcessTag.me
//$myOtherSingleton.tag = 14856
Singleton compartido
//Class VehicleFactory
property vehicleBuilt : Integer
shared singleton Class constructor()
This.vehicleBuilt := 0 //Número de vehículos construidos por la fábrica
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
Luego puede llamar al singleton cs.VehicleFactory para obtener un nuevo vehículo desde cualquier lugar de la aplicación en su máquina con una sola línea:
$vehicle:=cs.VehicleFactory.me.buildVehicle("truck")
Dado que la función buildVehicle() modifica el singleton cs.VehicleFactory (incrementando This.vehicleBuilt), debe agregar la palabra clave shared.
Singleton de sesión
En una aplicación de inventario, desea implementar un inventario de artículos utilizando singletons de sesión.
//class ItemInventory
property itemList : Collection:=[]
session singleton Class constructor()
shared function addItem($item:object)
This.itemList.push($item)
Al definir la clase ItemInventory como un singleton de sesión, asegúrese de que cada sesión y por lo tanto cada usuario tiene su propio inventario. Acceder al inventario del usuario es tan simple como:
//en una sesión usuario
$myList := cs.ItemInventory.me.itemList
//lista de elemento del usuario actual
local and server
In client/server architecture, local and server keywords allow you to specify where you want the function to be executed: client-side, or server-side. Controlling the execution location is useful for performance reasons or to implement business logic features.
La sintaxis formal es:
// declare a function to execute on a client in client/server
local Function <functionName>
// declare a function to execute on the server in client/server
server Function <functionName>
local and server keywords are only available for the functions of the following classes:
- ORDA data model classes
- shared or session singleton classes.
Generalidades
Supported functions have a default execution location when no location keyword is used. You can nevertheless insert a local or server keyword to modify the execution location, or to make the code more explicit.
| Supported functions | Ejecución por defecto | with local keyword | with server keyword |
|---|---|---|---|
| ORDA data model | on Server | The function is executed on the client if called on the client | |
| Shared or session singleton | Local | The function is executed on the server on the server instance of the singleton. If there is no instance of the singleton on the server, it is created. |
If local and server keywords are used in another context, an error is returned.
For a overall description of where code is actually executed in client/server, please refer to this section.
local
In a client/server architecture, the local keyword specifies that the function must be executed on the machine from where it is called.
The local keyword is useless for shared or session singleton functions, which are executed locally by default.
By default, ORDA data model functions are executed on the server. Suele ofrecer el mejor rendimiento, ya que sólo se envían por la red la petición de función y el resultado. However, for optimization reasons, you could want to execute a data model function on client. You can then use the local keyword.
Example: Calculating age
Dada una entidad con un atributo birthDate, queremos definir una función age() que sería llamada en un list box. Esta función puede ejecutarse en el cliente, lo que evita lanzar una petición al servidor para cada línea del list box.
En 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
In a client/server architecture, the server keyword specifies that the function must be executed on the server side.
The server keyword is useless for ORDA data model functions, which are executed on the server by default.
server function parameters and result must be streamable. For example, 4D.Datastore, File handle, or WebServer are non-streamable classes but 4D.File is streamable.
This feature is particularly useful in the context of remote user sessions, allowing you to implement the business logic in a session singleton to share it accross all the processes of the session, thus extending the functionalities of the Session command. In this case, you might want the relevant business logic to be executed on the server so that all the session information is gathered on the server.
By default, shared or session singleton functions are executed locally. Adding the server keyword in the class function definition makes 4D use the singleton instance on the server. Note that this can result of an instantiation of the singleton on the server if no instance exists yet.
For sessions singletons, the function is executed on the server in the corresponding singleton instance, i.e. the instance of the singleton for the current session.
If you declare a server Function in a shared singleton, then:
- you instantiate a singleton S1 on the client (named s1),
- you run s1.function() on the client.
If no instance of S1 exists on the server at that moment, S1 is instantiated on the server (the constructor is executed), and function() runs on that server instance. As a result, two instances of S1 can coexist (client-side and server-side), with distinct property values. In this case, s1.property is always accessed locally. It cannot be accessed on the server, for example from server-side code using direct dot notation (an error is returned).
Example: Administration singleton
The Administration shared singleton has a "server" function running the Process activity command. This singleton is instantiated on a remote 4D but the function returns the server activity on the server.
// Administration class
shared singleton Class constructor
// This function is executed on the server
server Function processActivity() : Object
return Process activity
Function localProcessActivity() : Object
return Process activity
Code running on the client:
var $localActivity; $serverActivity : Object
var $administration : cs.Administration
// The Administration singleton is instantiated on the 4D Client
$administration:=cs.Administration.me
// Get processes running on the remote 4D
$localActivity:=$administration.localProcessActivity()
// Get processes and sessions running on 4D Server
$serverActivity:=$administration.processActivity()
Example: Session singleton
You store your users in a Users table and handle a custom authentication. You use a session singleton for the authentication:
// UserSession session singleton class
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
To provide the current user to 4D clients, the singleton exposes a user computed property got from the server:
server Function get user() : cs.UsersEntity
return ds.Users.get(Session.storage.userInfo.userId)