Singletony ve 4D

Automaticky přeloženo z Deepl

4D 20 R5 přináší vývojářům výkonnou funkci: Singletony!

Návrhový vzor singleton vytváří jedinou instanci třídy přístupnou v celé aplikaci.

Tento vzor nabízí mnoho výhod, včetně:

  • hostitelství pro meziprocesové hodnoty,
  • užitkové třídy,
  • základ pro návrhový vzor factory,
  • a mnoho dalších.

Čtěte dále a získejte více informací o tomto novém konceptu!

4D má 2 typy singletonů: singletony, které jsou jedinečné pro každý proces, a sdílené singletony, které jsou jedinečné v rámci celé aplikace. Singletony jsou standardní objekty, zatímco sdílené singletony jsou sdílené objekty.

Definování singletonu je velmi snadné; stačí přidat klíčové slovo singleton do konstruktoru třídy:

singleton Class constructor()

Definování sdíleného singletonu je také velmi snadné; stačí použít klíčové slovo singleton ve sdílené třídě:

shared singleton Class constructor()

Od této chvíle můžete k singletonům snadno přistupovat prostřednictvím atributu me:

$singleton:=cs.SingletonClass.me

Atribut me je instance singletonu (v jiných jazycích se k ní často přistupuje přes funkci getInstance()). Je instancována při prvním přístupu k singletonu.

Příklady:

Singletony jsou velmi užitečné a očekáváme, že je začnete často používat. Domnívám se, že byste dali přednost příkladům singletonů před dlouhým popisem, proto jsem jich několik připravil.

Užitková třída

Začněme jednoduchým příkladem: třídou utility. Třída utility hostí mnoho užitečných funkcí, které se používají všude ve vaší aplikaci. Seskupení těchto funkcí do jediné třídy pomáhá udržovat kód, protože je velmi snadné najít všechny užitkové funkce a nezaneřádí vaše metody.

//Class UtilityClass
 
singleton Class constructor()
 
Function utilityFunction1()
 
Function utilityFunction2()
 
...

Od této chvíle můžete své užitkové funkce volat pomocí tohoto řádku:

cs.UtilityClass.me.utilityFunction1()

Websocket server wrapper

Dalším klasickým použitím singletonů je vytvoření obalů pro objekty, které by měly být přístupné všude ve vaší aplikaci, jako je například websocketový server. Uvažujme tuto třídu:

//WebSocketServerWrapper
 
singleton Class constructor()
 
$handler:=cs.myWebsocketServerHandler.new()
This.webSocketServer:=4D.WebSocketServer.new($handler; {dataType: “object”})
 
Function terminate()
 
This.webSocketServer.terminate()

Od této chvíle můžete spustit svůj webový server voláním:

CALL WORKER(“WebSocketServerWorker”; Formula(cs.WebSocketServerWrapper.me))

A ukončit jej voláním:

CALL WORKER(“WebSocketServerWorker”; Formula(cs.WebSocketServerWrapper.me.terminate()))

Factory .

Třetí příklad implementuje návrhový vzor: továrnu. Továrna má na starosti vytváření nových instancí objektů, v tomto případě objektů Vehicle pocházejících z 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

Díky tomu, že se jedná o Singleton, můžete tuto VehicleFactory zavolat a získat nové Vozidlo odkudkoli ve vašem procesu (nebo aplikaci, pokud ji uděláte sdílenou) pomocí jediného řádku:

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

V takovém případě tato továrna nedělá nic jiného, než že spočítá počet postavených vozidel, než vám vrátí nové vozidlo, ale myslím, že jste pochopili, o co jde.

Pokud chcete, aby továrna VehicleFactory byla jedinečná v celé vaší aplikaci, musíte k ní přidat klíčové slovo shared. Funkce buildVehicle modifikuje VehicleFuilt (inkrementací This.vehicleBuilt), takže k ní také musíte přidat sdílené klíčové slovo, aby se při volání a ukončení funkce automaticky volalo use a end use.

Hodnoty mezi procesy

Dalším klasickým použitím singletonů je hostování meziprocesových hodnot, které budete používat v celé aplikaci. Zde je příklad takového singletonu:

//Class InterprocessSingleton
 
shared singleton Class constructor()
 
This.version:=2
This.buildNumber:=1056

Z něj můžete velmi snadno přistupovat například ke globálním proměnným:

cs.InterprocessSingleton.me.version

Tip: Někdy chcete inicializovat meziprocesové hodnoty při spuštění aplikace, typicky uvnitř metody On Application Startup, a v takovém případě může být nutné předat konstruktoru singletonu parametry jako v příkladu níže:

//Class InterprocessSingleton
 
shared singleton Class constructor($file : 4D.File)
 
$json:=$file.getText()
$settingsJson:=JSON Parse($json)
 
This.version:=$settingsJson.version
This.buildNumber:=$settingsJson.buildNumber

V tomto případě hodnoty version a buildNumber pocházejí ze souboru JSON. V případě singletonů existuje způsob, jak zavolat konstruktor s parametry voláním funkce new(). Například v našem případě:

$myFile:=File("/RESOURCES/settings.json")
cs.InterprocessSingleton.new($myFile)

Musíte si dát pozor, aby volání funkce new() bylo prvním přístupem k singletonu. Volání funkce new() po přístupu k singletonu již nebude volat konstruktor třídy.

Zvláštní poděkování

Zvláštní poděkování patří Chrisi Belangerovi, který navrhl přidání atributu me pro přístup k singletonu.

Doufám, že jsou pro vás singletony stejně vzrušující jako pro nás. Máte-li k nim nějaké dotazy, neváhejte je položit na fóru 4D.

Nicolas Brachfogel
• Product Owner & Senior Developer • Nicolas Brachfogel nastoupil do 4D v roce 2017 jako senior vývojář (4D server a sítě). Jako Product Owner, který řídí vydání Apple Silicon, má na starosti psaní uživatelských příběhů a jejich převod do funkčních specifikací a také zajišťuje, aby implementace funkcí vyhovovaly potřebám zákazníků. Nicolas, absolvent Institut Supérieur d'Informatique Appliquée (INSIA), začal svou kariéru jako softwarový vývojář v roce 2001. Po několika letech kódování v Javě a C++ se specializoval na vývoj klient-server pro společnosti zabývající se videohrami. Jako serverový vývojář/architekt úspěšně pracoval na serverových architekturách mnoha her (Dofus Arena, Drakerz, Trivial Pursuit Go!).