Callbacks

Brugen af callback-funtkioner giver os mulighed for at pakke funktionalitet, som ellers ville kræve en tilpasning til den bestemte kontekst, ind som standardfunktionalitet der blot kalder et sæt callbackfunktioner der håndterer det kontekstspecifikke i forbindelse med funktionaliteten.

Et klassisk eksempel er en sorteringsrutine, der i princippet kan bruges til hvilken som helst datastruktur man måtte ønske. Sorteringskriterierne er typisk specifikke fra datastruktur til datastruktur.

Sorteringsfunktionen kunne f.eks. implementere den velkendte bubblesortalgoritme (se senere i denne artikel) og benytte callback-funktioner til at beslutte, om det aktuelle element skal byttes med det efterfølgende eller om det skal blive i sin aktuelle position. Bubblesortalgoritmen beskæftiger sig, i sin simpleste form, kun med at undersøge, hvorvidt to elementer i en samling skal bytte plads eller ej. Det er callback-funktionens ansvar, at beskæftige sig med reglerne for, hvorvidt elementerne skal bytte plads eller ej, da det, ideelt set, er callback-funktionen der kender reglerne for datastrukturen.

En løsning i VBScript

Når man har kodet andet end VBScript, savner man til tider muligheden for at kunne benytte hjemmelavede events. VBScript understøtter ikke umiddelbart denne feature, så der er ikke meget at gøre ved det... eller det vil sige, lidt kan vi da gøre.

Rettelse: Callbacks i VBScript er faktisk muligt i et vist omfang - via GetRef. Så denne artikel er mest relevant i det tilfælde dine callbacks skal benyttes i forbindelse med kald til metoder i objekter, eller hvor funktionen ikke ligger i det globale scope. Læs mere om GetRef, hvordan den kan udnyttes og hvilke begrænsninger der i forbindelse med GetRef her.

Der findes i VBScript en måde hvorpå man på kørselstidspunktet kan udføre kode, dvs. VBS-kode som ligger i en streng og som kan påvirkes/ændres på kørselstidspunktet. Denne måde faciliteres af kommandoen "Execute".

Med Execute i baglommen, kan vi måske opnå noget af det vi søger (dog ikke helt så elegant og med et performancehit (dvs. at det altså negativ indflydelse på den hastighed hvormed vores kode udføres!), men det kan måske være med til at øge kodens generelle genanvendelighed og dermed spare os på andre områder...

Lad os tage et eksempel for lige at snuse til hvad Execute formår. Her er det en simpel kommando der udføres med Execute:

Execute "Response.Write(""Dette er en test af dynamisk udførsel af kode!"")"

Bemærk at strengen skal behandles som en normal VBScript streng, dvs. anførselstegn skal escapes på sædvanlige VBS-manér, med dobbelt anførselstegn. Ud over det, er formålet og resultatet af den viste Execute vist ikke svært at gennemskue.

En anden ting man bemærker, er at vi kan kalde/benytte de samme globale objekter i en Execute som vi kan normalt (her var det så Response-objektet der blev brugt).

Callback i praksis

En måde at lave et callback på i VBS er som følger:

function bubblesort(data, strCompareFunc)
  dim idx, idy, tmp, cmpVal
  dim maxIterationer

  maxIterationer = ubound(data) - 1

  for idy = maxIterationer to 0 step -1
    for idx = 0 to idy
      ' Kald den angivne comparer-funktion med to sæt data som skal sammenlignes
      Execute "cmpVal = " & strCompareFunc & "(data(idx), data(idx+1))" 

      ' Hvis den første er større end den anden, så skal de byttes rundt
      if cmpVal > 0 then
        tmp = data(idx)
        data(idx) = data(idx + 1)
        data(idx + 1) = tmp
      end if
    next
  next

  ' returner array'et i den sorterede form
  bubblesort = data
end function

' "Comparer" der sorterer strenge i stigende alfabetisk orden
function cmpString(firstVal, nextVal)
  cmpString = strComp(firstVal, nextVal, vbTextCompare)
end function

' "Comparer" der sorterer strenge i faldende alfabetisk orden
function cmpStringRev(firstVal, nextVal)
  cmpStringRev = strComp(firstVal, nextVal, vbTextCompare) * -1
end function

' "Comparer" der sorterer tal i stigende orden
function cmpNumbers(firstVal, nextVal)
  cmpNumbers = firstVal - nextVal
end function

' "Comparer" der sorterer tal i faldende orden
function cmpNumbersRev(firstVal, nextVal)
  cmpNumbersRev = firstVal - nextVal * -1
end function

Kaldet til sorteringsrutinen kunne se således ud:

arr = Array("H", "D", "K", "A", "L", "F")

' sorter arr i stigende orden
arr = bubblesort(arr, "cmpString")
' sorter arr i faldende orden
arr = bubblesort(arr, "cmpStringRev")

og i en komprimeret form:

arr = bubblesort(Array("H", "D", "K", "A", "L", "F"), "cmpString")

Som du måske har luret, skal der ikke ændres noget i bubblesort-funktionen selvom vi skifter datatypen ud (sålænge du benytter valuetype data, altså ikke objekter). Du skal bare sørge for at levere en comparer-funktion som kan genkende din datastruktur og fortælle sorteringsfunktionen hvilken dataklump der er den største/mindste.

Callback-metode kan anvendes til mange andre opgaver som pakker kompleksiteten ved selve opgaven væk og gør den mere genanvendelig (f.eks. filtrering af data, isolering af databaselag, sortering som vist her osv.), det er bare et spørgsmål om at bruge fantasien ;-)

Nu er vi vist klar til at springe videre til events... eller hvad?

Hvis ja, kan du læse videre her...

 
Sidst opdateret: 04-09-2010 23:46:42
Tilmeld link | Tilføj Link | Tilføj Link | @-begynder
Erklæring om beskyttelse af personlige oplysninger

nope.dk - Danmarks Website Chart