Programmazione orientata agli oggetti in ANSI-C. Delegati

Avendo trovato parecchi difetti all'idea delle classi di base astratte, abbiamo bisogno di cercare una idea migliore per le funzioni di callback.

Pensiamo quindi al fatto che nel caso del callback due sono le parti in gioco: l'oggetto client vuole essere chiamato e l'host deve effettuare la chiamata. Chiaramente, l'oggetto client deve farsi identificare dall'host se vuole che quest'ultimo gli spedisca messaggi. Il client non ha necessità di fare nient'altro se l'host può chiedere al client quali callbacks è in grado di accettare, ossia a quali metodi è in grado di rispondere.

E' importante sottolineare che il nostro punto di vista è cambiato: un oggetto è ora parte dello scenario per il callback. Chiameremo tale oggetto un delegato. Non appena un delegato si presenta all'host, l'host controlla quali callbacks tale delegato può gestire e successivamente l'host effettua le sole chiamate che il delegato si aspetta di ricevere (ossia quelle che può ricevere).

Come esempio implementiamo un semplice framework per un filtro di testo, ossia un programma che legge linee da standard input o da files specificati come argomenti, li manipola e scrive il risultato sullo standard output.

Come possibile applicazione prendiamo in considerazione il programma che conta le linee e i caratteri in un file di testo. Ecco il programma principale che può essere specificato come parte del file d'implementazione Wc.dc.

int main (int argc, char * argv [])
{ void * filter = new(Filter(), new(Wc()));
return mainLoop(filter, argv);
}

Creiamo un oggetto generale filter e diamogli la dignità di delegato di un oggetto di un'applicazione specifica Wc per contare le linee e i caratteri. Filter riceve gli argomenti del nostro programma ed esegue il mainLoop() con i callbacks all'oggetto Wc.

% WcClass: Class Wc: Object {
unsigned lines; // lines in current file
unsigned allLines; // lines in previous files
unsigned chars; // bytes in current file
unsigned allChars; // bytes in previous files
unsigned files; // files completed
%—
int wc (_self, const Object @ filter, \
const char * fnm, char * buf);
int printFile (_self, const Object @ filter, \
const char * fnm);
int printTotal (_self, const Object @ filter);
%}

I metodi in Wc non fanno nulla tranne che il conteggio di linee e caratteri e naturalmente restituiscono il risultato. Wc() è chiamato con un buffer che contiene una linea:

% Wc wc { // (self, filter, fnm, buf)
%casts
++ self —> lines;
self —> chars += strlen(buf);
return 0;
}

Una volta che un singolo file viene analizzato, printFile() effettua il report delle statistiche e le aggiunge al totale che man mano varia.

% Wc printFile { // (self, filter, fnm)
%casts
if (fnm && strcmp(fnm, "—"))
printf("%7u %7u %s\n",
self —> lines, self —> chars, fnm);
else
printf("%7u %7u\n", self —> lines, self —> chars);
self —> allLines += self —> lines, self —> lines = 0;
self —> allChars += self —> chars, self —> chars = 0;
++ self —> files;
return 0;
}

Fnm è un argomento che contiene il nome del file correntemente in uso. Può essere un puntatore a null o un segno meno, in questo caso non mostreremo il nome del file in output.

Infine, printTotal() mostra il totale se printFile() è stato chiamato più di una volta:

% Wc printTotal { // (self, filter)
%casts
if (self —> files > 1)
printf("%7u %7u in %u files\n",
self —> allLines, self —> allChars, self —> files);
return 0;
}

Wc si occupa del solo conteggio. Non si preoccupa degli argomenti a linea di comando, di aprire o leggere i file, etc. I nomi dei file sono usati solo per etichettare l'output e non hanno altro significato all'infuori di questo.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend