4D 20 R5 ofrece una poderosa funcionalidad para desarrolladores: ¡Singletons!
El diseño patrón singleton crea una instancia única de una clase accesible en toda la aplicación.
Este patrón ofrece muchos beneficios, incluyendo:
- un wrapper para las variables interproceso,
- clases utilitarias,
- una base para el diseño patrón de la fábrica,
- y muchas más.
Siga leyendo para obtener más información sobre este nuevo concepto.
4D tiene 2 tipos de singletons: los singletons, que son únicos por proceso y los singletons compartidos, que son únicos en toda la aplicación. Los singletons son objetos estándar, mientras que los singletons compartidos son objetos compartidos.
Definir un singleton es extremadamente fácil; basta con añadir la palabra clave singleton al constructor de una clase:
singleton Class constructor()
Definir un singleton compartido también es muy sencillo; basta con utilizar la palabra clave singleton en una clase compartida:
shared singleton Class constructor()
A partir de ese momento, puede acceder fácilmente a sus singletons a través del atributo me:
$singleton:=cs.SingletonClass.me
El atributo me es la instancia del singleton (a menudo accesible a través de la función getInstance() en otros lenguajes). Se instanciará la primera vez que acceda a su singleton.
Ejemplos
Los singletons son muy útiles, y esperamos que empiece a utilizarlos mucho. Pienso que preferirá ejemplos de singletons en lugar de una larga descripción, así que he preparado unos cuantos.
Clase utiliTARIA
Empecemos con un ejemplo sencillo: la clase utilitaria. La clase utilitaria alberga muchas funciones utilitarias que se utilizan en todas partes en su aplicación. Agrupar estas funciones en una sola clase ayuda a mantener su código, ya que es muy fácil encontrar todas sus funciones utilitarias, y no abarrotan sus métodos.
//Class UtilityClass
singleton Class constructor()
Function utilityFunction1()
Function utilityFunction2()
...
A partir de ese momento, puede llamar a sus funciones utilitarias con esta línea:
cs.UtilityClass.me.utilityFunction1()
wrapper Websocket server
Otro uso clásico de los singletons es crear wrappers para los objetos que deben ser accesibles en cualquier parte de su aplicación, como websocket server. Consideremos esta clase:
//WebSocketServerWrapper
singleton Class constructor()
$handler:=cs.myWebsocketServerHandler.new()
This.webSocketServer:=4D.WebSocketServer.new($handler; {dataType: “object”})
Function terminate()
This.webSocketServer.terminate()
A partir de ese momento, puede iniciar su Webserver llamando a:
CALL WORKER(“WebSocketServerWorker”; Formula(cs.WebSocketServerWrapper.me))
Y terminarlo llamando a:
CALL WORKER(“WebSocketServerWorker”; Formula(cs.WebSocketServerWrapper.me.terminate()))
Fábrica
El tercer ejemplo implementa un patrón de diseño: la fábrica. La fábrica se encarga de crear nuevas instancias de objetos, en este caso, objetos Vehicle procedentes de un VehicleFactory:
//Class VehicleFactory
property vehicleBuilt:=0 //Number of vehicles built by the factory
shared singleton Class constructor()
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
Gracias a su estado Singleton, puede llamar a esta VehicleFactory para obtener un nuevo vehiculo desde cualquier parte de su proceso (o aplicación si la hace compartida) con una sola línea:
$vehicle:=cs.VehicleFactory.me.buildVehicle("truck")
En ese caso, esta fábrica no hace mucho más que contar el número de vehículos construidos antes de devolver su nuevo vehículo, pero creo que capta la idea.
Si quiere que la VehicleFactory sea única en toda su aplicación, necesita añadirle la palabra clave shared. La función buildVehicle modifica el VehicleFactory (incrementando This.vehicleBuilt), por lo que también necesitas añadirle la palabra clave shared para que use y end use sean llamados automáticamente al llamar y salir de la función.
VaRIABLEs entre procesos
Otro uso clásico de los singletons es alojar variables interproceso que utilizará en toda su aplicación. Aquí tiene un ejemplo de singleton:
//Class InterprocessSingleton
shared singleton Class constructor()
This.version:=2
This.buildNumber:=1056
Desde ahí, puede acceder a sus variables globales muy fácilmente, por ejemplo:
cs.InterprocessSingleton.me.version
Consejo: a veces, querrá inicializar sus variables interproceso al inicio de su aplicación, normalmente dentro del método On Application Startup, y en tal caso, puede que necesite pasar parámetros al constructor singleton como en el ejemplo de abajo:
//Class InterprocessSingleton
shared singleton Class constructor($file : 4D.File)
$json:=$file.getText()
$settingsJson:=JSON Parse($json)
This.version:=$settingsJson.version
This.buildNumber:=$settingsJson.buildNumber
En ese caso, los valores de version y buildNumber provienen de un archivo JSON. En el caso de los singletons, hay una forma de llamar al constructor con parámetros llamando a la función new(). Por ejemplo, en nuestro caso:
$myFile:=File("/RESOURCES/settings.json")
cs.InterprocessSingleton.new($myFile)
Hay que tener cuidado de que la llamada a new() sea la primera vez que se accede al singleton. Llamar a new() después de que se haya accedido al singleton ya no llamará al constructor de la clase.
Agradecimientos especiales
Quiero agradecer especialmente a Chris Belanger, que sugirió añadir el atributo me para acceder a un singleton.
Espero que los singletons sean tan emocionantes para ustedes como lo son para nosotros. Si tiene alguna pregunta sobre ellos, no dude en hacerla en el foro de 4D.