Estratto del documento

TimeRange

Case study sull'implementazione di un valore

Compatibilità: dotNET 2.0+

Anno 2017/2018

TimeRange 1 di 30

Indice generale

1 Introduzione............................................................................................4

1.1 Problema: NYC Marathon...........................................................................4

2 Un approccio procedurale........................................................................5

2.1 Opzione 1: nessun modello........................................................................5

2.2 Opzione 2: utilizzare dei campi stringa.......................................................5

2.3 Opzione 3: record.......................................................................................6

2.4 Rappresentare il tempo degli atleti: intervallo di tempo............................7

2.4.1 Implementare le operazioni sui tempi....................................................................7

2.5 Implementazione dei requisiti....................................................................8

2.6 Conclusioni.................................................................................................9

3 Un approccio object oriented.................................................................10

3.1 Oggetto TimeRange: dati + operazioni.....................................................10

3.1.1 Analisi della classe: “funzionamento” del codice object oriented.......................12

3.2 Conclusioni...............................................................................................14

4 Adottare i principi di progettazione OO..................................................15

4.1 Stabilire la modalità di creazione dei tempi.............................................15

4.2 Rappresentare un intervallo di tempo in secondi.....................................16

4.3 Ottimizzare e rendere coerente l’implementazione.................................17

4.3.1 Definire in modo chiaro lo stato dell'oggetto.......................................................18

4.3.2 Utilizzare una struttura.........................................................................................19

4.4 Incapsulare completamente TimeRange..................................................20

4.4.1 “Proteggere” lo stato dell'oggetto........................................................................20

4.4.2 Incapsulamento: non dipendere dall'implementazione.......................................20

5 “Standardizzare” TimeRange..................................................................23

5.1 Definire gli operatori standard.................................................................23

5.2 Eseguire il parsing da stringa....................................................................24

5.3 Informazioni sul valore.............................................................................26

5.3.1 Informazioni sul tipo.............................................................................................26

5.4 Creazione di tempi sulla base di valori totali............................................27

6 Considerazioni finali...............................................................................28

6.1 Utilità e qualità di TimeRange..................................................................28

6.1.1 Validità..................................................................................................................28

6.1.2 Allineamento agli standard dei tipi primitivi........................................................28

TimeRange 2 di 30

6.1.3 Risoluzione temporale e intervallo di variazione..................................................29

6.2 “Immutabilità” di TimeRange...................................................................29

TimeRange 3 di 30

1 Introduzione

In questo tutorial utilizzo un semplice problema di programmazione come mezzo per affrontare le problematiche connesse all'implementazione di un nuovo tipo di dato. L'obiettivo finale è quello di realizzare un tipo analogo a

TimeSpan

il quale incapsula un intervallo di tempo.

A partire dalla definizione del problema, procederò per gradi, utilizzando dapprima un approccio procedurale, per arrivare progressivamente a un corretta soluzione OO. Metterò in evidenza i limiti delle soluzioni adottate di volta in volta, mostrando come superarli e dimostrando che l'implementazione di (o tipo analogo) rappresenta il risultato ideale.

TimeSpan

(Nota a margine: non realizzerò un'implementazione identica a quella di

TimeSpan

ma una molto più semplice e che non prende in considerazione le gestione dell'overflow di valori interi)

1.1 Problema: NYC Marathon

Si desiderano elaborare i tempi dei partecipanti dalla gara della maratona olimpica. Questi sono memorizzati in un file CSV:

Cenci Leonardo, Italia, 4:06:16

Kamworor Geoffrey, Kenya, 2:10:23

Ghirmay Ghebreslassie, Eritrea, 2:11:4

Feyisa Lilesa, Etiopia, 2:09:54

Eliud Kipchoge, Kenya, 2:8:44

Munyo Mutai, Uganda, 2:11:49

Galen Rupp, USA, 2:10:05

Alphonce Simbu, Tanzania, 2:11:15

Jared Ward, USA, 2:11:30

...

Occorre eseguire le seguenti operazioni:

  • Visualizzare l'elenco in ordine di classifica (in base ai tempi).
  • Visualizzare la differenza tra il tempo migliore e quello peggiore.

Vincoli

Non è possibile utilizzare il tipo

TimeSpan

(Nota bene: per semplicità non si fa riferimento ai requisiti relativi alla UI, alla posizione del file e alle azioni da intraprendere nel caso in cui il contenuto del file non sia valido.)

TimeRange 4 di 30

2 Un approccio procedurale

Davanti a un problema simile la prima questione è: come rappresentare i dati. Naturalmente, il modello scelto deve avere la funzione di favorire l'implementazione delle richieste del problema: visualizzazione delle informazioni sugli atleti ed elaborazioni sulla base dei loro tempi.

Di seguito fornisco alcune opzioni, delle quali le prime due sono volutamente inadeguate. (Ma che evidenziano l'importanza di fornire un'appropriata rappresentazione dei dati.)

2.1 Opzione 1: nessun modello

È la scelta più semplice: ogni atleta è rappresentato da una stringa che memorizza la riga corrispondente del file.

class Program

{ static void Main(string[] args)

{ string[] atleti = CaricaAtleti("Maratona.txt");

//... elabora i dati

}

static string[] CaricaAtleti(string nomeFile)

{ return File.ReadAllLines(nomeFile);

}

}

Il codice di caricamento è semplicissimo; d'altra parte, avere le informazioni nella forma:

" , , "

Tadesse Abraham Svizzera 2:11:42

rende complicata l'implementazione dei requisiti, poiché implica l'estrazione dei dati (nominativo, nazione e tempo) per ogni operazione da realizzare.

2.2 Opzione 2: utilizzare dei campi stringa

Ogni atleta è rappresentato da tre campi stringa; i dati degli atleti sono memorizzati in una matrice di tre colonne.

static string[,] CaricaAtleti(string nomeFile)

{ string[] righe = File.ReadAllLines(nomeFile);

string[,] atleti = new string[righe.Length, 3];

for (int i = 0; i < righe.Length; i++)

{ string[] campi = righe[i].Split(',');

atleti[i, 0] = campi[0].Trim();

atleti[i, 1] = campi[1].Trim();

atleti[i, 2] = campi[2].Trim();

}

return atleti;

}

TimeRange 5 di 30

I dati di un atleta sono memorizzati separatamente, ma la loro elaborazione non risulta molto più semplice rispetto a prima: ogni dato è individuato attraverso una coppia di coordinate nella matrice. Inoltre, i tempi sono memorizzati come stringhe e dunque non è possibile utilizzarli direttamente nelle operazioni necessarie a soddisfare i requisiti del problema.

2.3 Opzione 3: record

L'uso di un consente di rappresentare il singolo atleta in modo significativo:

record

class Atleta

{ public string Nominativo;

public string Nazione;

public string Tempo;

}

static Atleta[] CaricaAtleti(string nomeFile)

{ string[] righe = File.ReadAllLines(nomeFile);

Atleta[] atleti = new Atleta[righe.Length];

for (int i = 0; i < righe.Length; i++)

{ string[] campi = righe[i].Split(',');

atleti[i].Nominativo = campi[0].Trim();

atleti[i].Nazione = campi[1].Trim();

atleti[i].Tempo = campi[2].Trim();

}

return atleti;

}

Il tipo incapsula il concetto di atleta e consente di gestire gli atleti come oggetti del tipo

atleta

Atleta

appropriato, mantenendo la possibilità di processare i loro attributi: Nominativo, Nazione e Tempo.

Nominativo Nazione Tempo

Per quest'ultimo è tuttora utilizzato il tipo

string

; ciò non consente di eseguire direttamente operazioni sui tempi. Ad esempio, il tempo di:

"Tadesse Abraham, Svizzera, "

2:11:42

è maggiore del tempo di: "Eliud Kipchoge, Kenya, "

2:8:44

ma così non risulterebbe da un confronto tra stringhe, poiché la prima è minore della seconda.

Le opzioni considerate finora sollevano l’identica questione: la rappresentazione dei dati mediante dei tipi adeguati è fondamentale, poiché sono i tipi a stabilire i vincoli e le operazioni ammissibili su di essi. C# fornisce i tipi primitivi (int, char, string, double, etc), i quali definiscono una rappresentazione di interi, caratteri, stringhe, etc. In alcune situazioni sono sufficienti, in altre è necessario definire nuovi tipi:

  • Perché non esiste un tipo che possa rappresentare il dato: vedi, ad esempio, i singoli atleti;
  • Perché i tipi utilizzabili non forniscono le operazione richieste: vedi i tempi degli atleti.

TimeRange 6 di 30

2.4 Rappresentare il tempo degli atleti: intervallo di tempo

Elaborare il tempo degli atleti significa poter conoscere ore, minuti e secondi, confrontare due tempi, ottenere l'intervallo che intercorre tra due tempi. Un approccio è quello di rappresentare un singolo tempo mediante un record:

class TimeRange

{ public int Ore;

public int Minuti;

public int Secondi;

}

...

class Atleta

{ public string Nominativo;

public string Nazione;

public TimeRange Tempo;

}

2.4.1 Implementare le operazioni sui tempi

TimeRange si limita a memorizzare i dati; al codice applicativo va la responsabilità di implementare le operazioni necessarie:

static TimeRange Parse(string tempo) // ottiene un tempo da una stringa

{ string[] campi = tempo.Split(':');

var t = new TimeRange();

t.Ore = int.Parse(campi[0]);

t.Minuti = int.Parse(campi[1]);

t.Secondi = int.Parse(campi[2]);

return tr;

}

static string ToString(TimeRange t) // converte un tempo in stringa

{ string segno = (t.Ore < 0 || t.Minuti < 0 || t.Secondi < 0) ? "-" : "";

return string.Format("{0}{1}:{2}:{3}", segno,

Math.Abs(t.Ore), Math.Abs(t.Minuti), Math.Abs(t.Secondi));

}

static int TempoTotale(TimeRange t) // ottiene i secondi totali del tempo

{ return t.Ore * 3600 + t.Minuti * 60 + t.Secondi;

}

static TimeRange Intervallo(TimeRange t1, TimeRange t2) // ottiene l'intervallo di tempo

{ // che intercorre tra due tempi

var tr = new TimeRange();

int scarto = TempoTotale(t1) - TempoTotale(t2);

tr.Ore = scarto / 3600 % 3600;

tr.Minuti = scarto / 60 % 60;

TimeRange 7 di 30

tr.Secondi = scarto % 60;

return tr;

}

static int Confronta(TimeRange t1, TimeRange t2) // confronta due tempi e restituisce:

{ // -1, 0, 1 in base al fatto che il primo

int sect1 = TempoTotale(t1); // sia minore, uguale, maggiore del secondo

int sect2 = TempoTotale(t2);

if (sect1 > sect2)

return 1;

if (sect1 < sect2)

return -1;

return 0;

}

2.5 Implementazione dei requisiti

Sulla scorta dei metodi precedenti, si possono implementare i requisiti:

static void Main(string[] args)

{ Atleta[] atleti = CaricaAtleti("Maratona.txt");

Ordina(atleti);

Visualizza(atleti);

Atleta primo = atleti[0];

Atleta ultimo = atleti[atleti.Length - 1];

TimeRange scarto = Intervallo(ultimo.Tempo, primo.Tempo);

Console.WriteLine("\nTempo fra ultimo e primo = {0}", ToString(scarto));

}

static Atleta[] CaricaAtleti(string nomeFile)

{ string[] righe = File.ReadAllLines(nomeFile);

Atleta[] atleti = new Atleta[righe.Length];

for (int i = 0; i < righe.Length; i++)

{ string[] campi = righe[i].Split(',');

atleti[i] = new Atleta();

atleti[i].Nominativo = campi[0].Trim();

atleti[i].Nazione = campi[1].Trim();

atleti[i].Tempo = Parse(campi[2]);

}

return atleti;

}

static void Visualizza(Atleta[] atleti)

{ Console.WriteLine("{0,-25} {1,-15} {2}\n", "Nominativo", "Nazione",

Anteprima
Vedrai una selezione di 7 pagine su 30
Time Range - Case Study Pag. 1 Time Range - Case Study Pag. 2
Anteprima di 7 pagg. su 30.
Scarica il documento per vederlo tutto.
Time Range - Case Study Pag. 6
Anteprima di 7 pagg. su 30.
Scarica il documento per vederlo tutto.
Time Range - Case Study Pag. 11
Anteprima di 7 pagg. su 30.
Scarica il documento per vederlo tutto.
Time Range - Case Study Pag. 16
Anteprima di 7 pagg. su 30.
Scarica il documento per vederlo tutto.
Time Range - Case Study Pag. 21
Anteprima di 7 pagg. su 30.
Scarica il documento per vederlo tutto.
Time Range - Case Study Pag. 26
1 su 30
Sintesi

TimeRange: case study sull'implementazione di un valore

Introduzione

In questo tutorial utilizzo un semplice problema di programmazione come mezzo per affrontare le problematiche connesse all'implementazione di un nuovo tipo di dato. L'obiettivo finale è quello di realizzare un tipo analogo a TimeSpan, il quale incapsula un intervallo di tempo. A partire dalla definizione del problema, procederò per gradi, utilizzando dapprima un approccio procedurale, per arrivare progressivamente a una corretta soluzione OO. Metterò in evidenza i limiti delle soluzioni adottate di volta in volta, mostrando come superarli e dimostrando che l'implementazione di TimeSpan (o tipo analogo) rappresenta il risultato ideale.

(Nota a margine: non realizzerò un'implementazione identica a quella di TimeSpan, ma una molto più semplice e che non prende in considerazione la gestione dell'overflow di valori interi)

Un approccio procedurale

Davanti a un problema simile la prima questione è: come rappresentare i dati. Naturalmente, il modello scelto deve avere la funzione di favorire l'implementazione delle richieste del problema: visualizzazione delle informazioni sugli atleti ed elaborazioni sulla base dei loro tempi.

Di seguito fornisco alcune opzioni, delle quali le prime due sono volutamente inadeguate. (Ma che evidenziano l'importanza di fornire un'appropriata rappresentazione dei dati.)

D/illustrazione/soddisfatti o rimborsati
Acquista con carta o PayPal
Scarica i documenti tutte le volte che vuoi