Resultatberäkning på djupet
Denna sida beskriver hur beräkningar går till och hur de kan skrivas samt vad man bör tänka på. Löpande i dokumentet finns kodexempel där vi visar på olika sätt att skriva en beräkning. Vi har försökt att skriva så författare av resultatberäkning utan teknisk bakgrund skall förstå men ibland behöver tyvärr använda oss av tekniska termer då det krävs.
Gå direkt till rubriken:
Beräkningar i 1177 formulärhantering
På en formulärmall kan en eller flera beräkningar skapas som skall utföras baserat på ett besvarat formulär.
Beräkningen/beräkningarna utförs automatiskt när ett formulär besvaras.
En beräkning blir en kodsnutt som skall exekveras. Det är författarens ansvar att beräkningen görs på ett korrekt och effektivt sätt samt att man följer Formulärtjänstens regler.
Beräkningstyper
Vi har idag stöd för en typ av beräkningar och det är "inera:form-engine:drools-java:1". Om man använder Fristående personalgränssnittet används detta automatiskt. Om resultatberäkningsmotorn, vilket är den IT-komponent där beräkningen utförs, ser en beräkning av typen "inera:form-engine:drools-java:1" på mallen så kommer denna utföras.
Andra anslutna tjänster såsom Cosmic, EyeDoc, Provisio mfl. kanske redan har stöd för beräkningar och de kan då spara dessa på en mall som en egen typ och senare själva göra beräkningar på det besvarade formuläret. Det är då självklart viktigt att man anger en annan typ än den som resultatberäkningsmotorn känner till och som är unik för anropande system.
Drools och 1177 formulärhantering
Stödet för beräkningstypen 'inera:form-engine:drools-java:1' bygger på Drools (kie) som är en regelmotor byggd med programmeringsspråket Java.
Vi erbjuder ett delmängd av funktionerna i Drools, t.ex kan man bara ha en regel (rule) som vi kallar beräkning och denna är något reducerad. Vi använder oss också av dialekten Java när en beräkning skrivs. Mer utförlig beskrivning om detta hittar du längre ner.
Hur går en beräkning till?
Struktur
En beräkning består av två block, when och then som avslutas med end.
when
... (LHS)
then
... (RHS)
end
WHEN blocket innehåller ett eller flera villkor som skall vara uppfyllda för att beräkningen skall utföras. Denna delen kallas ofta LHS, left hand side.
THEN blocket innehåller de beräkningar som skall utföras då villkoret i WHEN blocket är uppfyllt. Denna delen kallas ofta RHS, right hand side
Exempel
when
$q: Questions()
eval($q.get("vikt") != null)
eval($q.get("längd") != null)
eval($q.get("längd") > 0)
then
double bmi = $q.get("vikt") / ($q.get("längd")/100 * $q.get("längd")/100);
outcome.set(bmi);
end
Fakta
Fakta är något som vi vill använda i vår beräkning. Fakta från formuläret är en lista med alla frågor och dess svar, namnet på denna lista är Questions
.
Questions måste man själv göra tillgänglig som en egen variabel, i exemplet nedan kallar vi variabeln för $q
.
Questions
innehåller då nyckel/värde par där nyckel är Frågans id och värde är svaret på frågan.
Svaret på en fråga i faktan representeras av en Double i Java som är ett flyttal.
Det finns vissa villkor som måste vara uppfyllda för att en fråga skall vara med som fakta:
En fråga måste ha ett unikt id, Frågans id (
questionId
)En fråga kan bara ha ett svar, flervalsfrågor stöds inte i nuläget
En fråga utan svar (
null
) tas inte med som fakta till beräkningen.Frågor av typen tal och skala (number, range) ingår med dess svarsvärde.
Frågor av typen rullgardin och enval (
radio
,matrixradio
ochselect
) ingår och där svaret är svarsalternativets ordningstal (answerAlternativeNumber
)
when
$q: Questions() // här gör vi Questions tillgänglig med namnet $q
eval($q.get("vikt") != null)
eval($q.get("längd") != null)
eval($q.get("längd") > 0)
then
.......
end
Beskrivning av objektet Questions
Retur | Metod | Beskrivning |
java.lang.Double | get(java.lang.String questionId) | Returnera svarsvärde för fråga med id questionId |
java.lang.Double | get(java.lang.String questionId, java.lang.Double defaultValue) | Returnera svarsvärde för fråga med id questionId. Om svarsvärde är null returneras defaultValue |
java.lang.Double | get(java.lang.String questionId, java.lang.Integer defaultValue) | Returnera svarsvärde för fråga med id questionId. Om svarsvärde är null returneras defaultValue |
Resultat
Resultatet för beräkningen, som vi själva skall sätta, finns alltid tillgängligt i then
-blocket med namnet outcome
.
Outcome har ett värde (value
) och är av Java typen Double som är ett flyttal.
Outcome har en metod för att sätta värdet och denna metoden har namnet set, Outcome.set(Double value)
.
Beskrivning av objektet Outcome
Retur | Metod | Beskrivning |
void | set(java.lang.Double value) | Sätt värde för resultat |
Kommentarer i beräkningen
Ibland kan det finnas behov av skriva kommentarer i sin beräkning. Det finns två typer av kommenterar, enrads- och flerradkommentar.
Enradskommentar skrivs med två snedstreck //
och flerradskommentar skrivs med symbolen /*
för att starta kommentaren och */
för att avsluta kommentaren
Variabler
Man kan skapa egna variabler som sedan kan användas i en formel. Man måste själv sätta vilken datatyp som avses för variabeln och det är Javas datatyper, primitiver och klasser, som finns tillgängliga att användas.
Tänk på att syntaxen för variabelnamn skiljer på versaler och gemener vilket innebär att namnet vikt
inte är samma som Vikt
.
Se längre ner för beskrivning av Javas datatyper
Syntax och Java dialekt
För att skriva beräkningar så använder vi oss av Drools egna DSL samt Java syntax. Drools DSL (Domain Specific Language) är specific syntax och för att skriva Drools regler använder vi Drools Rule Language (DRL), dock är det bara en delmängd av DRL:en som används vid en resultatberäkning. Det är alltså Java syntax till stor del som styr hur en beräkning skrivs och i Java syntax så finns det en del regler som måste följas men det innebär också att vi får tillgång till Javas operatorer, flödeskontroller, primitiver och standard klasser. För att skriva enkla beräkningar så behöver man inte vara en fullfjädrad programmerare utan det räcker långt att man tittar på de kodexempel som finns för att göra sin beräkning. Om man sedan vill göra en mer avancerad beräkning så hjälper det självklart om man har grundläggande förståelse om programmering och då gärna specifikt för Java.
En viktig sak som är lätt att missa är att varje operation i when
-blocket skall avslutas med semikolon (;
) som är java syntax.
Vi har också tillgång till Drools egna operatorer som då används i when-blocket.
Java operatorer
En operator används när du vill utföra en operation på en variabel. Nedan följder några vanliga operatorer:
| addition, subtraktion, multiplikation, division |
| lika med, inte lika med |
| större än, mindre än, större än eller lika med, mindre än eller lika med |
| logiskt och (AND), logiskt eller (OR) |
| tilldela en variabel ett värde |
Läs mer om Java operatorer här: Operators
Nedan ser du exempel på hur olika operatorer kan användas.
Flödeskontroller
I then-blocket så vill man kanske styra flödet beroende på variabelvärden men använder då Javas flödeskontroller för att åstadkomma detta.
Flödeskontroller som finns tillgängliga i Java.
| används för villkor |
| används för iteration |
| uthopp |
Nedan ser du exempel på hur olika flödeskontroller kan användas.
Datatyper
När vi skriver en beräkning så har vi också tillgång till Javas primitiver och standard klasser.
Viktigt är att se och förstå skillnaden på en primitiv och och dess motsvarande klass. Till exempel har primitiven double
en motsvarande klass med namnet Double
.
En primitiv börjar alltid med en gemen och en klass börjar alltid med en versal.
En primitiv kan aldrig vara
null
.
Om man inte har behov av att använda null-värden så rekommenderas att använda primitiver, alltså de som börjar med en gemen.
För den som är intresserad så finns bra beskrivning om Javas primitiver och standard klasser.
Drools operatorer och nyckelord
Då Drools DRL har en egen syntax så finns flera operatorer och nyckelord som kan användas men dock inte alla. Det som syns mest av Drools för en författare av resultatberäkning är nyckelorden when
, then
och end
samt det som kan användas i when
-blocket.
Om du är intresserad av Drools och vill läsa mer så hittar det information på deras hemsida och i deras dokumentation.
Att tänka på
Att skriva resultatberäkning är till viss del programmering och man behöver veta och tänka på vissa saker för att det skall bli bra och av hög kvalité.
Kontrollera Null värden
Man skall alltid kontrollera att ett värde inte är null
innan man försöker använda det för annars får man ett fel vid beräkningen. Att ett värde är null
för en fråga kan bland annat bero på att frågan inte är satt som obligatorisk. Om det är ett fakta som man vet skall finnas så skall kontrollen göras i when
-blocket eftersom ingen beräkning då kommer utföras.
Nedan ser du en kontroll på att flera villkor måste vara uppfyllda och de binds ihop med och
. Kontrollen nedan skall läsas enligt följande: vikt
skall inte vara null och längd
skall inte vara null. Vi ser även att vi lagt till att längd
skall vara större än 0, eftersom vi inte vill dividera med 0
Om man vill använda ett icke obligatorsikt svar i then
-blocket så med en if
-sats. I det fiktiva exemplet nedan vill vi ge alla som är äldre än 55 år lite bonus (3) på sitt framräknade bmi värde. Koden nedan skall då läsas: om variabeln alder
inte är null
och variabeln alder
är större än 55
då vill man utföra det som finns inom klammarparantes ({}
)
Vi skulle också kunna använde den inbyggda möjligheten som finns att returna ett standardvärde om det verkliga svarsvärdet är null
.
Dividera inte med noll
Ett vanligt fel att är att man inte kontrollerar värdet innan det används. Om man till exempel försöker dividera med en variabel som har värdet noll (0
) resulterar det i felet divide by zero
.
I följande exempel kontrollerar vi svaret för fråga med id längd
att det inte är null
och är större än
noll
.