Fondamenti di Informatica T2 Modulo 2 - unibo.it
Transcript of Fondamenti di Informatica T2 Modulo 2 - unibo.it
Università di Bologna – A.A. 2008/2009
Fondamenti di Informatica T2
Modulo 2
Università degli Studi di Bologna
Facoltà di Ingegneria
Corso di Laurea in Ingegneria Informatica
Anno accademico 2008/2009
2
Veicoli
2
• Si desidera realizzare una o più classi che permettano di
modellare diverse tipologie di veicolo.
• Come per il caso della categoria concettuale animale, un
veicolo rappresenta una categoria concettuale astratta
• Non possono esistere istanze di veicolo, perché NON
ESISTE UN VEICOLO QUALSIASI
• Le istanze apparterranno invece alle sue sottoclassi
concrete
Università di Bologna – A.A. 2008/2009
3
Veicoli
3
• L’entità astratta veicolo è caratterizzata da:
– la marca, che rappresenta la casa costruttrice del
veicolo
– il modello, che rappresenta la versione di veicolo
realizzata dalla casa costruttrice
• ed è descritta tramite:
– la tipologia del veicolo
– lo scopo per cui il veicolo viene impiegato (es. trasporto
persone, trasporto merci, etc.)
– il luogo in cui si muove il veicolo (es. terra ferma, aria,
etc.)
– il mezzo tramite cui si muove il veicolo (es. ruote,
superfici alari, etc.)
4
Veicoli
4
• L’entità astratta veicolo verrà quindi modellata tramite la classe astratta Veicolo, caratterizzata da:
– metodi accessor per accedere alla marca e al modello
del veicolo
– un insieme di metodi per accedere alle stringe
descrittive del veicolo; quindi per accedere a:
• la tipologia del veicolo (tipologia)
• lo scopo per cui il veicolo viene impiegato (scopo)
• il luogo in cui si muove il veicolo (doveSiMuove)
• il mezzo tramite cui si muove il veicolo (siMuoveTramite)
– La rappresentazione a stringa di veicolo (toString)
Università di Bologna – A.A. 2008/2009
5
Veicoli
5
• La rappresentazione interna di un veicolo in termini di
marca e modello, è indipendente dallo specifico veicolo
• Una prima rappresentazione a stringa del veicolo (tramite la toString) può essere definita indipendentemente dallo
specifico veicolo, in termini della sua rappresentazione
interna e delle stringhe descrittive
6
Veicoli
6
• Le stringhe descrittive associate all’entità veicolo dipendono
dallo specifico veicolo modellato
→ è impossibile definire in Veicolo i metodi associati alle
stringhe descrittive
→ i metodi associati alle stringhe descrittive devono essere
astratti
toString utilizza i
metodi astratti!
Università di Bologna – A.A. 2008/2009
7
Veicoli
7
• Una possibile classificazione per i veicoli:
Si muove in aria
Si muove sulla terra ferma
• Non è ancora possibile definire i restanti metodi astratti
→VeicoloAereo e VeicoloTerrestre sono entrambe
classi astratte
8
Veicoli
8
• Aereo e Aliante rappresentano due possibili sottoclassi
concrete di VeicoloAereo:
Università di Bologna – A.A. 2008/2009
9
Veicoli
9
• Aereo modella l’entità veicolo aereo
– la cui tipologia è Aereo
– che si muove in aria (eredita da VeicoloAereo)
– tramite superfici alari e organo propulsore
– è adibito al trasporto di persone o merci
è possibile definire i
restanti metodi astratti!
10
Veicoli
10
Un aliante è caratterizzato anche dal numero di posti
disponibili e dalla dimensione dell’apertura
alare (espressa in metri)
vengono aggiungte nuove
informazioni rispetto algenerico veicolo
la toString di Veicolo
viene ridefinita
• Aliante modella l’entità aliante
– la cui tipologia è Aliante
– che si muove in aria (eredita da VeicoloAereo)
– tramite superfici alari, senza alcun organo propulsore
– è adibito solo al trasporto di persone
Università di Bologna – A.A. 2008/2009
11
Veicoli
11
• AereoDiLinea rappresenta una possibile specializzazione
di Aereo:
12
Veicoli
12
Un aereo di linea è caratterizzato anche dal
numero di posti disponibili
aggiunge nuove
informazioni rispetto algenerico veicolo …
• AereoDiLinea modella l’entità aereo di linea
– la cui tipologia è Aereo di Linea
– che si muove in aria (eredita da VeicoloAereo)
– tramite superfici alari e organo propulsore (eredita da Aereo)
– è adibito solo al trasporto di persone (ridefinisce scopo
definito in Aereo)
Università di Bologna – A.A. 2008/2009
13
Veicoli
13
• Autovettura e Autocarro rappresentano due possibili
sottoclassi concrete di VeicoloTerrestre:
14
Veicoli
14
• Autovettura modella l’entità autovettura
– la cui tipologia è Autovettura
– che si muove sulla superficie terrestre (eredita da VeicoloTerrestre)
– tramite ruote
– è adibita solo al trasporto di persone
Un’autovettura è caratterizzata anche dal
numero di posti disponibili
aggiunge nuove
informazioni rispetto algenerico veicolo …
Università di Bologna – A.A. 2008/2009
15
Veicoli
15
Un autocarro è caratterizzato da una capacità massima
di carico (espressa in quintali) e dal tipo di ruote
aggiunge nuove
informazioni rispetto algenerico veicolo …
• Autocarro modella l’entità autocarro
– la cui tipologia è Autocarro
– che si muove sulla terra ferma (eredita da VeicoloTerrestre)
– tramite ruote
– è adibito solo al trasporto di merce
16
Veicoli
16
• Automobile e Autobus rappresentano due possibili
specializzazioni di Autovettura:
Università di Bologna – A.A. 2008/2009
17
Veicoli
17
Un’automobile è caratterizzata anche dalnumero di porte e dal
numero di volumi
aggiunge nuove
informazioni rispetto allagenerica autovettura …
• Automobile modella l’entità automobile
– la cui tipologia è Automobile
– che si muove sulla terra ferma (eredita da VeicoloTerrestre)
– tramite ruote (eredita da Autovettura)
– è adibita solo al trasporto di un numero limitato di persone (ridefinisce scopo definito in Autovettura)
18
Veicoli
18
• Autobus modella l’entità autobus
– la cui tipologia è Autobus
– che si muove sulla terra ferma (eredita da VeicoloTerrestre)
– tramite ruote (eredita da Autovettura) ed
– adibito solo al trasporto di una collettività di persone (ridefinisce scopo definito in Autovettura)
Università di Bologna – A.A. 2008/2009
19
Veicoli
19
• Furgone rappresenta una possibile specializzazione di
Autocarro:
20
Veicoli
20
Un furgone è caratterizzata anche dal
fatto di essere finestrato o meno
aggiunge nuove
informazioni rispetto algenerico autocarro …
• Furgone modella l’entità furgone
– la cui tipologia è Furgone
– che si muove sulla terra ferma (eredita da VeicoloTerrestre)
– tramite ruote (eredita da Autocarro) ed
– adibito solo al trasporto di merce (eredita da Autocarro)
Università di Bologna – A.A. 2008/2009
21
• Si desidera avere la seguente organizzazione dei
package:
Veicoli
veicoli
Veicolo.java
…
Cartella
di lavoro
Test.java
Furgone.java
22
import veicoli.*;
public class Test
{
public static void main(String args[])
{
Veicolo v[] = {
new Autovettura("Mercedes-Benz", "Berlina", 4),
new Automobile("Fiat", "Panda", 5, 5, 2),
new Autobus("Mercedes-Benz", "O530 Citaro", 28),
new Furgone("Volkswagen", "Caddy", 510,
"singole", false),
new AereoDiLinea("Boeing", "707-300", 250),
new Aliante("Briegleb", "BG 12", 1, 15.24) };
…
22
È possibile fare ciò perché sono anche oggetti di tipo Veicolo!
Testing
Università di Bologna – A.A. 2008/2009
23
…
for(int i = 0; i < v.length; i++)
{
System.out.println(v[i]);
}
}
}
23
Testing
• Tramite il polimorfismo verranno richiamati i metodi definiti
dall’oggetto effettivamente referenziato. Ad esempio:
– quando viene stampato l’oggetto v[3], verrà richiamata la
toString definita per gli oggetti della classe Furgone
– la toString di v[0] richiamerà il metodo tipologia
(definito come metodo astratto nella classe Veicolo)
definito per gli oggetti della classe Autovettura
24
Soluzione - Veicoli
package veicoli;
public abstract class Veicolo
{
protected String marca;
protected String modello;
public Veicolo(String marca, String modello)
{
this.marca = marca;
this.modello = modello;
}
…
}
24
Università di Bologna – A.A. 2008/2009
25
Soluzione - Veicoli…
public String getMarca()
{
return marca;
}
public String getModello()
{
return modello;
}
public String toString()
{
return tipologia() + " " + marca + "/" + modello
+ ": veicolo " + scopo() + ", si muove "
+ doveSiMuove() + " tramite “
+ siMuoveTramite() + ".";
}
… 25
Metodi accessor.Metodi accessor
26
Soluzione - Veicoli
…
public abstract String tipologia();
public abstract String scopo();
public abstract String doveSiMuove();
public abstract String siMuoveTramite();
26
Metodi astratti
Università di Bologna – A.A. 2008/2009
27
Soluzione - Veicoli
package veicoli;
public abstract class VeicoloAereo extends Veicolo
{
public VeicoloAereo(String marca, String modello)
{
super(marca, modello);
}
public String doveSiMuove()
{
return “in aria”;
}
}
27
28
Soluzione - Veicoli
package veicoli;
public abstract class VeicoloTerrestre extends Veicolo
{
public VeicoloTerrestre(String marca, String modello)
{
super(marca, modello);
}
public String doveSiMuove()
{
return “sulla terra ferma”;
}
}
28
Università di Bologna – A.A. 2008/2009
29
Soluzione - Veicolipackage veicoli;
public class Aliante extends VeicoloAereo
{
private int numeroPosti;
private double aperturaAlare;
public Aereo(String marca, String modello, int
numeroPosti, double aperturaAlare)
{
super(marca, modello);
this.numeroPosti = numeroPosti;
this.aperturaAlare = aperturaAlare;
}
…
}29
30
Soluzione - Veicoli…
public int getNumeroPosti()
{
return numeroPosti;
}
public double getAperturaAlare()
{
return aperturaAlare;
}
public String tipologia()
{
return “Aliante”;
}
…
30
Università di Bologna – A.A. 2008/2009
31
Soluzione - Veicoli…
public String scopo()
{
return “adibito al trasporto di persone”;
}
public String siMuoveTramite()
{
return “superfici alari senza organo motopropulsore”;
}
public String toString()
{
return super.toString() + " Il veicolo ha un'apertura
alare di " + getAperturaAlare() + " metri e può
ospitare un massimo di " + getNumeroPosti()
+ (getNumeroPosti() == 1 ? " persona" : "
persone") + ".";
} 31
32
Soluzione - Veicoli
package veicoli;
public class Aereo extends VeicoloAereo
{
public Aereo(String marca, String modello)
{
super(marca, modello);
}
public String tipologia()
{
return “Aereo”;
}
…
}
32
Università di Bologna – A.A. 2008/2009
33
Soluzione - Veicoli
…
public String scopo()
{
return “adibito al trasporto di persone o merci”;
}
public String siMuoveTramite()
{
return “superfici alari e organo motopropulsore”;
}
33
34
Soluzione - Veicolipackage veicoli;
public class AereoDiLinea extends Aereo
{
private int numeroPosti;
public AereoDiLinea(String marca, String modello, int
numeroPosti)
{
super(marca, modello);
this.numeroPosti = numeroPosti;
}
public int getNumeroPosti()
{
return numeroPosti;
}
…
} 34
Università di Bologna – A.A. 2008/2009
35
Soluzione - Veicoli…
public String tipologia()
{
return “Aereo di linea”;
}
public String scopo()
{
return “adibito al trasporto di persone”;
}
public String toString()
{
return super.toString() + " Il veicolo può ospitare un
massimo di " + getNumeroPosti() +
(getNumeroPosti() == 1 ? " persona" : " persone")
+ ".";
}35
36
Soluzione - Veicolipackage veicoli;
public class Autovettura extends VeicoloTerrestre
{
protected int numeroPosti;
public Autovettura(String marca, String modello, int
numeroPosti)
{
super(marca, modello);
this.numeroPosti = numeroPosti;
}
public int getNumeroPosti()
{
return numeroPosti;
}
…
} 36
Università di Bologna – A.A. 2008/2009
37
Soluzione - Veicoli…
public String tipologia()
{
return “Autovettura”;
}
public String scopo()
{
return “adibito al trasporto di persone”;
}
public String siMuoveTramite()
{
return “ruote”;
}
…
37
38
Soluzione - Veicoli
…
public String toString()
{
return super.toString() + " Il veicolo può ospitare un
massimo di " + getNumeroPosti() +
(getNumeroPosti() == 1 ? " passeggero" : "
passeggeri")
+ ".";
}
38
Università di Bologna – A.A. 2008/2009
39
Soluzione - Veicoli
package veicoli;
public class Autocarro extends VeicoloTerrestre
{
protected double capacitàMassima;
protected String tipoRuote;
public Autocarro (String marca, String modello, double
capacitàMassima, String tipoRuote)
{
super(marca, modello);
this.capacitàMassima = capacitàMassima;
this.tipoRuote = tipoRuote;
}
…
}
39
40
Soluzione - Veicoli…
public String getTipoRuote()
{
return tipoRuote;
}
public double getCapacitàMassima()
{
return capacitàMassima;
}
public String tipologia()
{
return “Autocarro”;
}
…
40
Università di Bologna – A.A. 2008/2009
41
Soluzione - Veicoli…
public String scopo()
{
return “adibito al trasporto di merci”;
}
public String siMuoveTramite()
{
return “ruote”;
}
public String toString()
{
return super.toString() + " Il veicolo è dotato di
ruote " + getTipoRuote () + " ha una capacità
massima di " + getCapacitàMassima() +
((getCapacitàMassima() == 1) ? " quintale." :
" quintali.");
}41
42
Soluzione - Veicoli
package veicoli;
public class Automobile extends Autovettura
{
private int numeroPorte;
private int numeroVolumi;
public Automobile(String marca, String modello, int
numeroPosti, int numeroPorte, int numeroVolumi)
{
super(marca, modello, numeroPosti);
this.numeroPorte = numeroPorte;
this.numeroVolumi = numeroVolumi;
}
…
}42
Università di Bologna – A.A. 2008/2009
43
Soluzione - Veicoli…
public int getNumeroPorte()
{
return numeroPorte;
}
public int getNumeroVolumi()
{
return numeroVolumi;
}
public String tipologia()
{
return “Automobile”;
}
…
43
44
Soluzione - Veicoli…
public String scopo()
{
return “adibito al trasporto di un numero limitato di
persone”;
}
public String toString()
{
String stringaPadre = super.toString();
return stringaPadre.substring(0, stringaPadre.length()
- 1) + ", possiede " + getNumeroPorte() + "
porte, ed è a " + getNumeroVolumi()
+ ((getNumeroVolumi() == 1) ? " volume." :
" volumi.");
} 44
Università di Bologna – A.A. 2008/2009
45
Soluzione - Veicolipackage veicoli;
public class Autobus extends Autovettura
{
public Autobus(String marca, String modello, int
numeroPosti)
{
super(marca, modello, numeroPosti);
}
public String tipologia()
{
return “Autobus”;
}
public String scopo()
{
return “adibito al trasporto collettivo di persone”;
}
}45
46
Soluzione - Veicolipackage veicoli;
public class Furgone extends Autocarro
{
private boolean finestrato;
public Furgone(String marca, String modello, double
capacitàMassima, String tipoRuote, boolean finestrato)
{
super(marca, modello, capacitàMassima, tipoRuote);
this.finestrato = finestrato;
}
public boolean isFinestrato()
{
return finestrato;
}
…
}46
Università di Bologna – A.A. 2008/2009
47
Soluzione - Veicoli…
public String tipologia()
{
return “Furgone”;
}
public String toString()
{
String stringaPadre = super.toString();
return stringaPadre.substring(0, stringaPadre.length()
- 1) + (isFinestrato() ? " ed è" : " e non è")
+ " finestrato.";
}
47
48
import veicoli.*;
public class Test
{
public static void main(String args[])
{
Veicolo v[] = {
new Autovettura("Mercedes-Benz", "Berlina", 4),
new Automobile("Fiat", "Panda", 5, 5, 2),
new Autobus("Mercedes-Benz", "O530 Citaro", 28),
new Furgone("Volkswagen", "Caddy", 510,
"singole", false),
new AereoDiLinea("Boeing", "707-300", 250),
new Aliante("Briegleb", "BG 12", 1, 15.24) };
…
48
Soluzione - Veicoli
Università di Bologna – A.A. 2008/2009
49
…
for(int i = 0; i < v.length; i++)
{
System.out.println(v[i]);
}
}
}
49
Testing
50
Extended Phone Plan
Utilizzando i sorgenti messi a disposizione per Operator e Band, realizzare l’infrastruttura per i
piani tariffari vista in aula, in particolare:
Parte 1
1. Implementare la classe PhonePlan astratta
contenente i servizi base per tutti i PhonePlan
2. Implementare la classe PrecisePlan che realizza
l’algoritmo “preciso” di calcolo dei costi di una chiamata
3. Realizzare i test JUnit necessari alla verifica del corretto funzionamento di PrecisePlan
50
Università di Bologna – A.A. 2008/2009
51
Testing• Evitare di perdere tempo per testare Operator e Band che
sono dati
• Creare Operator e Band di test nel minimo numero
indispensabile
– Un solo Operator
– Due Band:
• Entrambe su tutti i giorni della settimana
• La prima attiva su una parte della giornata, la seconda sulla restante
parte
• Verificare il funzionamento dell’algoritmo di calcolo del
costo della chiamata nel caso in cui la chiamata sia:
– su una sola fascia oraria (un metodo di test)
– a cavallo di due fasce orarie (un altro metodo di test)
51
52
Extended Phone Plan
Parte 1 – Diagramma UML
52
class plans
Precis ePlan
+ getCallCost(Date, Date, String, String) : double
+ PrecisePlan(String, int, int, Operator[])
PhonePlan
- interval: int
- name: String
- operators: Operator ([])
- startCallCost: double
+ getCallCost(Date, Date, String, String) : double
+ getCallCost(Phon eCall) : double
+ getInterval() : int
+ getName() : String
# getOperatorByName(String) : Operator
+ getStartCallCo st() : double
+ isValid() : boolean
# PhonePlan(String, int, int, Operator[])
tlc::Operator
- bands: Band ([])
- name: String
+ getBands() : Band[]
+ getCostPerInterva l(Date) : double
+ getName() : String
+ isValid() : boolean
+ Operator(String, Band[])
- selectBandInDay(DayOfWeekEnum) : Band[]
- validateDay(DayOfWeekEnum) : boolean
tlc::Band
- combinedDays: DayOfWeekEnum ([])
- costPerInterval: double
- endTime: SimpleTime
- startTime: SimpleTime
+ Band(SimpleTime, SimpleTime, DayOfWeekEnum[], double)
+ getCombinedDays() : DayOfWeekEnum[]
+ getCostPerInterval() : double
+ getEndTime() : SimpleTime
+ getStartTime() : SimpleTime
+ isInBand(Date) : boolean
+ isValid() : boolean
+ sortByStartTime(Band[]) : void
-operators
1. .*
-bands 1. .*
Università di Bologna – A.A. 2008/2009
53
Extended Phone Plan
Parte 2
1. Implementare la classe astratta Option
2. Implementare PrecisePhonePlanWithOption
(sottoclasse di PhonePlan)
3. Realizzare i test JUnit necessari alla verifica del
corretto funzionamento di PrecisePhonePlanWithOption:
• Implementare la classe DummyOption che consenta di
verificare il funzionamento:
1. del sistema di override dei parametri del piano – verificare che
il risultato in termini di costi di una chiamata sia quello atteso
2. del sistema di notifica – verificare che il numero di notifiche
effettuate sia quello atteso
53
54
Extended Phone Plan
Parte 2 – Diagramma UML
54
class plans
PhonePlan
- interval: int
- name: String
- operators: Operator ([])
- startCallCost: double
+ getCallCost(Date, Date, String, String) : double
+ getCallCost(Phon eCall) : double
+ getInterval() : int
+ getName() : String
# getOperatorByName(String) : Operator
+ getStartCallCo st() : double
+ isValid() : boolean
# PhonePlan(String, int, int, Operator[])
PrecisePlanWithOptions
- options: Option ([])
- findApplicableOption(Date, Operator, String) : Option
+ getCallCost(Date, Date, String, String) : double
+ getOptions() : Option[]
+ getStartCallCost(Date, Op erator, String) : double
+ PrecisePlanWithOptions(String, int, int, Operator[], Option[])
Option
+ getCostPerInterval() : double
+ getInterval() : int
+ getStartCallCost() : double
+ isApplicable(Date, Operator, String) : boolean
+ notifyIntervalAccounted() : void
+ overridesCostPerInterval() : boolean
+ overridesInterval() : boolean
+ overridesStartCallCost() : boolean
-options
1. .*
Università di Bologna – A.A. 2008/2009
55
EPP - Notifiche
• Domanda
– Come si fa a conoscere il numero di notifiche effettuate all’opzione
(ovvero il numero di volte che l’opzione è stata utilizzata per
contabilizzare)?
• Risposta:
– Nel metodo che consente le notifiche inserire un contatore che deve essere visibile da fuori (getX)
– Si costruisce un nuovo piano (PrecisePhonePlanWithOptions)
passando l’opzione DummyOption di cui occorre mantenere un
riferimento
– Al termine del test verificare che il valore del contatore contenuto nella DummyOption abbia il valore atteso in base alle chiamate di
cui è stato calcolato il costo
55
56
DummyOption - Dettagli• È un’opzione di test e non è detto che debba avere pienamente
senso…
• Risponde sempre true a isApplicable
• Risponde true ai vari overrideX – avere cura di restituire valori
sensati (e semplici) nei corrispondenti metodi getX
• All’invocazione del metodo di notifica (notifyIntervalAccounted –
invocato dal piano che usa l’opzione) viene incrementato un
contatore
• Al termine del test verificare se il contatore ha raggiunto il valore
atteso ovvero se l’opzione è stata usata il numero di volte previsto
56
Università di Bologna – A.A. 2008/2009
57
EPP – Note • Notare che il testing di PrecisePhonePlanWithOptions
è indipendente dal testing delle opzioni concrete
“commerciali”
• È stato inserito in un ambiente artificiale di cui la nuova DummyOption fa parte
• Ed è stato sollecitato per verificare le attese
• Si può fare di meglio?
– Eliminare le altre dipendenze concrete (Operator) – come?
– In fase di test, utilizzare un’implementazione alternativa di Operator (più semplice) che NON coinvolga l’entità Band
57
58
Note generali sul testing
• L’oggetto/componente argomento di test dovrebbe essere
quanto più isolato possibile…
• …ed immerso in un ambiente il più artificiale possibile…
• …in modo da evitare che il funzionamento (o il NON
funzionamento) del componente stesso sia influenzato dal
funzionamento (o NON funzionamento) degli oggetti che
fanno parte del suo ambiente
58
Università di Bologna – A.A. 2008/2009
59
Note generali sul testing
• In termini di design, è necessario che una classe
abbia quante meno dipendenze concrete possibile
– per massimizzare la riusabilità – l’unità riusabile è
composta dall’oggetto più tutte le sue dipendenze
concrete)
– per facilitare il testing – l’oggetto è completamente
isolabile e può essere immerso in un ambiente
completamente artificiale: gli oggetti concreti al contorno
sono appositamente studiati solo per i test
59
60
Opzioni• Implementare l’opzione YouMeAndTheOther
– Due numeri di telefono a tariffa flat (da definire)
– Intervallo di tariffazione a 60 secondi
– Nessuno scatto alla risposta
• Implementare l’opzione FlatTime
– Mette a disposizione un certo numero di minuti “prepagati” (definibili
all’atto della costruzione)
– Intervallo di tariffazione a 30 secondi
– Nessuno scatto alla risposta
• Verificare il corretto funzionamento delle opzioni
implementate (un test JUnit per ogni classe) prima di
utilizzarle all’interno di un piano
60
Università di Bologna – A.A. 2008/2009
61
Soluzione - PhonePlanpublic abstract class PhonePlan
{
private String name;
private int interval;
private double startCallCost;
private Operator[] operators;
protected PhonePlan(String name, int interval, int
startCallCost, Operator[] operators)
{
this.name = name;
this.interval = interval; //in millisecondi
this.startCallCost = startCallCost;
this.operators = operators;
}
…
} 61
PhonePlan modella un piano
telefonico astratto che
definisce solo ciò che è
indipendente da una specifica
implementazione.
62
Soluzione - PhonePlan…
public String getName()
{
return name;
}
public int getInterval()
{
return interval;
}
public double getStartCallCost()
{
return startCallCost;
}
public abstract double getCallCost(Date callStart, Date
callEnd, String destOperator, String destNumber);
…
62
getCallCost rappresenta
l’implementazione del calcolo del
costo di una chiamata
getCallCost deve essere
definito come metodo astratto.
Università di Bologna – A.A. 2008/2009
63
Soluzione - PhonePlan…
public double getCallCost(PhoneCall call)
{
return getCallCost(call.getCallStart(),
call.getCallEnd(), call.getDestOperator(),
call.getDestNumber());
}
public boolean isValid()
{
for (Operator operator : operators)
{
if (!operator.isValid())
return false;
}
return true;
}
… 63
64
Soluzione - PhonePlan…
protected Operator getOperatorByName(String operatorName)
{
Operator selected = null;
for (Operator o : operators)
{
if (o.getName().equals(operatorName))
{
selected = o;
break;
}
}
return selected;
}
…
64
Università di Bologna – A.A. 2008/2009
65
Soluzione - PrecisePlanpublic class PrecisePlan extends PhonePlan
{
public PrecisePlan(String name, int interval, int
startCallCost, Operator[] operators)
{
super(name, interval, startCallCost, operators);
}
@Override
public double getCallCost(Date callStart, Date callEnd,
String destOperator, String destNumber)
{
Operator selected = getOperatorByName(destOperator);
if (selected == null)
return -1;
…
}
}65
PrecisePlan definisce l’algoritmo “preciso” per il calcolo
del costo di una chiamata.
66
Soluzione – PrecisePlan…
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(callStart);
Date currentDateTime = cal.getTime();
double durationCost = 0;
while (currentDateTime.compareTo(callEnd) < 0)
{
durationCost +=
selected.getCostPerInterval(currentDateTime);
cal.setTime(currentDateTime);
cal.add(GregorianCalendar.MILLISECOND, getInterval());
currentDateTime = cal.getTime();
}
return getStartCallCost() + durationCost;
66
Università di Bologna – A.A. 2008/2009
67
Soluzione - PrecisePlanTestpublic class PrecisePlanTest
{
public static PrecisePlan createPlan()
{
return new PrecisePlan("TIM", 1000, 10, new Operator[]
{OperatorTest.createOperator()});
}
@Test
public void testGetCallCost()
{
PhonePlan plan = createPlan();
GregorianCalendar cal = new GregorianCalendar();
…
}
…
}67
68
Soluzione - PrecisePlanTest
…
cal.set(GregorianCalendar.DAY_OF_WEEK,
GregorianCalendar.WEDNESDAY);
cal.set(GregorianCalendar.HOUR_OF_DAY, 22);
cal.set(GregorianCalendar.MINUTE, 24);
cal.set(GregorianCalendar.SECOND, 0);
cal.set(GregorianCalendar.MILLISECOND, 0);
Date callStart = cal.getTime();
…
68
Crea l’inizio chiamata …
Università di Bologna – A.A. 2008/2009
69
Soluzione - PrecisePlanTest
…
cal.set(GregorianCalendar.DAY_OF_WEEK,
GregorianCalendar.WEDNESDAY);
cal.set(GregorianCalendar.HOUR_OF_DAY, 22);
cal.set(GregorianCalendar.MINUTE, 27);
cal.set(GregorianCalendar.SECOND, 0);
cal.set(GregorianCalendar.MILLISECOND, 0);
Date callEnd = cal.getTime();
double actual =
plan.getCallCost(callStart, callEnd, "TIM", "");
assertEquals(1810, actual);
}69
… crea la fine chiamataappartenente alla stessa
fascia oraria e …
… verifica che il costo della chiamata sia quello
che ci aspettiamo.
70
Soluzione - PrecisePlanTest…
@Test
public void testGetCallCost_CrossBand()
{
PhonePlan plan = createPlan();
GregorianCalendar cal = new GregorianCalendar();
cal.set(GregorianCalendar.DAY_OF_WEEK,
GregorianCalendar.WEDNESDAY);
cal.set(GregorianCalendar.HOUR_OF_DAY, 18);
cal.set(GregorianCalendar.MINUTE, 28);
cal.set(GregorianCalendar.SECOND, 0);
cal.set(GregorianCalendar.MILLISECOND, 0);
Date callStart = cal.getTime();
…70
Crea l’inizio chiamata …
Università di Bologna – A.A. 2008/2009
71
Soluzione - PrecisePlanTest
…
cal.set(GregorianCalendar.DAY_OF_WEEK,
GregorianCalendar.WEDNESDAY);
cal.set(GregorianCalendar.HOUR_OF_DAY, 18);
cal.set(GregorianCalendar.MINUTE, 31);
cal.set(GregorianCalendar.SECOND, 0);
cal.set(GregorianCalendar.MILLISECOND, 0);
Date callEnd = cal.getTime();
double actual = plan.getCallCost(callStart, callEnd,
"TIM", "");
assertEquals(3010, actual);
}
…
71
… crea la fine chiamataappartenente ad una
fascia oraria diversa e …
… verifica che il costo della chiamata sia quello
che ci aspettiamo.
72
Soluzione - PrecisePlanTest…
@Test
public void testGetCallCost_CrossBand_Dat()
{
PhonePlan plan = createPlan();
GregorianCalendar cal = new GregorianCalendar();
cal.set(GregorianCalendar.DAY_OF_WEEK,
GregorianCalendar.WEDNESDAY);
cal.set(GregorianCalendar.HOUR_OF_DAY, 23);
cal.set(GregorianCalendar.MINUTE,58);
cal.set(GregorianCalendar.SECOND, 0);
cal.set(GregorianCalendar.MILLISECOND, 0);
Date callStart = cal.getTime();
…72
Crea l’inizio chiamata …
Università di Bologna – A.A. 2008/2009
73
Soluzione - PrecisePlanTest
…
cal.set(GregorianCalendar.DAY_OF_WEEK,
GregorianCalendar.THURSDAY);
cal.set(GregorianCalendar.HOUR_OF_DAY, 0);
cal.set(GregorianCalendar.MINUTE, 0);
cal.set(GregorianCalendar.SECOND, 30);
cal.set(GregorianCalendar.MILLISECOND, 0);
Date callEnd = cal.getTime();
double actual = plan.getCallCost(callStart, callEnd,
"TIM", "");
assertEquals(1510, actual);
}
73
… crea la fine chiamataappartenente ad una
fascia oraria diversa e …
… verifica che il costo della chiamata sia quello
che ci aspettiamo.
74
Soluzione - Option
public abstract class Option
{
public abstract boolean isApplicable(Date istantTime,
Operator operator, String destNumber);
public abstract boolean overridesCostPerInterval();
public abstract double getCostPerInterval();
public abstract boolean overridesInterval();
public abstract int getInterval();
public abstract boolean overridesStartCallCost();
public abstract double getStartCallCost();
public abstract void notifyIntervalAccounted();
}74
Option modella un’entità che: 1) permette di ridefinire uno o
più parametri del piano tariffario; 2) può avere uno stato che cambia in base al suo utilizzo.
Università di Bologna – A.A. 2008/2009
75
Soluzione - PrecisePlanWithOptionspublic class PrecisePlanWithOptions extends PhonePlan
{
private Option[] options;
public PrecisePlanWithOptions(String name, int interval,
int startCallCost, Operator[] operators,
Option[] options)
{
super(name, interval, startCallCost, operators);
this.options = options;
}
public Option[] getOptions()
{
return options;
}
…
} 75
Contiene un insieme di opzioni di cui non conosce i dettegli implementativi!
PrecisePlanWithOption
modella un piano con opzioni.
76
…
@Override
public double getCallCost(Date callStart, Date callEnd,
String destOperator, String destNumber)
{
Operator selected = getOperatorByName(destOperator);
if (selected == null)
return -1;
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(callStart);
Date currentDateTime = cal.getTime();
double startCallCost =
getStartCallCost(currentDateTime, selected,
destNumber);
…
}
…
76
Soluzione - PrecisePlanWithOptions
Università di Bologna – A.A. 2008/2009
77
…
double durationCost = 0;
while (currentDateTime.compareTo(callEnd) < 0)
{
Option option =
findApplicableOption(currentDateTime, selected,
destNumber);
int intervalToAdd = getInterval();
if (option != null)
{
if (option.overridesInterval())
intervalToAdd = option.getInterval();
durationCost += option.getCostPerInterval();
option.notifyIntervalAccounted();
}
… 77
Sfrutta le opzioni nel calcolo del costo di una chiamata.
Sfrutta la prima opzione applicabile nel calcolo del costo di una chiamata.
Soluzione - PrecisePlanWithOptions
78
…
else
{
durationCost +=
selected.getCostPerInterval(currentDateTime);
}
cal.setTime(currentDateTime);
cal.add(GregorianCalendar.MILLISECOND,
intervalToAdd);
currentDateTime = cal.getTime();
}
return startCallCost() + durationCost;
}
78
Soluzione - PrecisePlanWithOptions
Università di Bologna – A.A. 2008/2009
79
…
public double getStartCallCost(Date currentTime,
Operator operator, String
destNumber)
{
Option option =
findApplicableOption(currentTime, operator,
destNumber);
return (option != null &&
option.overridesStartCallCost()) ?
option.getStartCallCost() : getStartCallCost();
}
…
79
Soluzione - PrecisePlanWithOptions
80
…
private Option findApplicableOption(Date istantTime,
Operator operator, String destNumber)
{
for (Option option : options)
{
if (option.isApplicable(istantTime, operator,
destNumber))
{
return option;
}
}
return null;
}
80
Recupera la prima opzione applicabile.
Soluzione - PrecisePlanWithOptions
Università di Bologna – A.A. 2008/2009
81
Soluzione - DummyOptionpublic class DummyOption extends Option
{
private int notificationCount;
public DummyOption()
{
notificationCount = 0;
}
public int getNotificationCount()
{
return notificationCount;
}
@Override
public double getCostPerInterval()
{
return 2;
}
…
}81
DummyOption è una classe
realizzata per verificare il corretto funzionamento di
PrecisePhonePlaneWithOption
82
Soluzione - DummyOption…
@Override
public int getInterval()
{
return 30000;
}
@Override
public double getStartCallCost()
{
return 0;
}
@Override
public boolean isApplicable(Date istantTime,
Operator operator, String destNumber)
{
return true;
}82
Università di Bologna – A.A. 2008/2009
83
Soluzione - DummyOption
…
@Override
public void notifyIntervalAccounted()
{
notificationCount++;
}
@Override
public boolean overridesCostPerInterval()
{
return true;
}
…
83
84
Soluzione - DummyOption
…
@Override
public boolean overridesInterval()
{
return true;
}
@Override
public boolean overridesStartCallCost()
{
return true;
}
84
Università di Bologna – A.A. 2008/2009
85
Soluzione - PrecisePlanWOptionsTestpublic class PrecisePlanWOptionsTest
{
public static PrecisePlanWithOptions createPlan()
{
return new PrecisePlanWithOptions("TIM", 1000, 10,
new Operator[] {OperatorTest.createOperator()},
new Option[] {new DummyOption()});
}
public static PrecisePlanWithOptions createPlan(Option[]
options)
{
return new PrecisePlanWithOptions("TIM", 1000, 10,
new Operator[] {OperatorTest.createOperator()},
options);
}
…
} 85
86
…
@Test
public void testGetCallCostDateDateStringString()
{
DummyOption1 option = new DummyOption1();
PrecisePlanWithOptions plan = createPlan(new Option[]
{ option });
GregorianCalendar cal = new GregorianCalendar();
cal.set(GregorianCalendar.DAY_OF_WEEK,
GregorianCalendar.WEDNESDAY);
cal.set(GregorianCalendar.HOUR_OF_DAY, 22);
cal.set(GregorianCalendar.MINUTE, 24);
cal.set(GregorianCalendar.SECOND, 0);
cal.set(GregorianCalendar.MILLISECOND, 0);
Date callStart = cal.getTime();
…86
Soluzione - PrecisePlanWOptionsTest
Università di Bologna – A.A. 2008/2009
87
…
cal.set(GregorianCalendar.DAY_OF_WEEK,
GregorianCalendar.WEDNESDAY);
cal.set(GregorianCalendar.HOUR_OF_DAY, 22);
cal.set(GregorianCalendar.MINUTE, 27);
cal.set(GregorianCalendar.SECOND, 0);
cal.set(GregorianCalendar.MILLISECOND, 0);
Date callEnd = cal.getTime();
double actual = plan.getCallCost(callStart, callEnd,
"TIM", "");
assertEquals(12, actual);
assertEquals(6, option.getNotificationCount());
}
…
87
Soluzione - PrecisePlanWOptionsTest
Verifica il sistema di override dei parametri del piano e il sistema di
notifica.
88
…
@Test
public void testGetStartCallCostDateOperatorString()
{
assertEquals(0.0, createPlan().getStartCallCost(new
Date(), OperatorTest.createOperator(), “MyNumber”));
}
88
Soluzione - PrecisePlanWOptionsTest
Università di Bologna – A.A. 2008/2009
89
public class YouMeAndTheOther extends Option
{
private String destNumber1;
private String destNumber2;
private double costPerInterval;
public YouMeAndTheOther(String destNumber1,
String destNumber2, double costPerInterval)
{
this.destNumber1 = destNumber1;
this.destNumber2 = destNumber2;
this.costPerInterval = costPerInterval;
}
public boolean overridesCostPerInterval()
{
return true;
}
…
}89
Soluzione - YouMeAndTheOther
Permette l’override del costo relativo all’intervallo di
tariffazione.
90
…
@Override
public double getCostPerInterval()
{
return costPerInterval;
}
@Override
public boolean isApplicable(Date istantTime,
Operator operator, String
destNumber)
{
return destNumber.equals(destNumber1) ||
destNumber.equals(destNumber2);
}
…
90
Soluzione - YouMeAndTheOther
L’opzione è applicabile solo se il destinatario della chiamata è
destNumber1 o destNumber2.
Università di Bologna – A.A. 2008/2009
91
…
@Override
public boolean overridesInterval()
{
return true;
}
@Override
public int getInterval()
{
return 30000;
}
@Override
public boolean overridesStartCallCost()
{
return true;
}
… 91
Soluzione - YouMeAndTheOther
Permette l’override dell’intervallo di tariffazione.
Permette l’override del costo relativo allo scatto alla risposta.
92
…
@Override
public double getStartCallCost()
{
return 0;
}
@Override
public void notifyIntervalAccounted()
{
}
@Override
public String toString()
{
return "You, Me And The Other - " + destNumber1 + " and
"
+ destNumber2;
} 92
Soluzione - YouMeAndTheOther
Università di Bologna – A.A. 2008/2009
93
public class FlatTime extends Option
{
private int flatPeriod;
public FlatTime(int flatPeriod)
{
this.flatPeriod = flatPeriod;
}
public boolean overridesCostPerInterval()
{
return true;
}
@Override
public double getCostPerInterval()
{
return 0;
}
… 93
Soluzione - FlatTime
Permette l’override del costo relativo all’intervallo di
tariffazione.
94
…
@Override
public boolean isApplicable(Date istantTime,
Operator operator, String destNumber)
{
return flatPeriod >= getInterval();
}
@Override
public boolean overridesInterval()
{
return true;
}
@Override
public int getInterval()
{
return 30000;
}
… 94
Soluzione - FlatTime
Permette l’override dell’intervallo di tariffazione.
E’ applicabile solo se il numero di minuti
prepagati corrente è maggiore dell’intervallo
di tariffazione.
Università di Bologna – A.A. 2008/2009
95
…
@Override
public boolean overridesStartCallCost()
{
return true;
}
@Override
public double getStartCallCost()
{
return 0;
}
…
95
Soluzione - FlatTime
Permette l’override del costo relativo allo scatto alla risposta.
96
…
@Override
public void notifyIntervalAccounted()
{
flatPeriod -= getInterval();
}
@Override
public String toString()
{
return "It's a Flat Time! - Minutes left: " +
((float)flatPeriod / 60000);
}
96
Soluzione - FlatTime