You are on page 1of 59

Item 1 - Considerare metodi statici factory invece dei costruttori

Il modo normale per una classe per consentire a un client di ottenere un'istanza di se stessa fornire un
costruttore pubblico . Vi un'altra tecnica che dovrebbe essere parte di ogni toolkit di un programmatore .
Una classe pu fornire un metodo pubblico statico factory , che semplicemente un metodo statico che
restituisce un'istanza della classe . Esempio : Questo metodo converte un valore primitivo booleano in un
riferimento a un oggetto booleano:
public static Boolean valueOf ( boolean b) {
return b ? Boolean.TRUE : Boolean.FALSE ;}
Si noti che un metodo statico factory non lo stesso del modello Factory Method dei Design Patterns. Il
metodo statico factory descritto in questo item non ha rilevanza con quello dei Design Patterns. Una classe
pu fornire i propri clienti attraverso metodi statici factory invece di, o in aggiunta a , costruttori . Fornire
un metodo statico factory invece di un pubblico costruttore presenta sia vantaggi che svantaggi .
1) Un vantaggio dei metodi statici factory che, a differenza costruttori , essi hanno nomi . Se i parametri
di un costruttore non li hanno , di per s ,descrivono l'oggetto che viene restituito , un metodo statico
factory con un nome ben scelto pi facile da utilizzare e il codice client risultante pi facile da leggere .
2) Un secondo vantaggio di metodi statici factory che, a differenza costruttori , essi non sono tenuti a
creare un nuovo oggetto ogni volta che vengono invocati . Questo consente classi immutabili ( item 15 ) per
utilizzare le istanze precostruite, per evitare di creare oggetti duplicati inutili . Il metodo Boolean.valueOf (
boolean) illustra questa tecnica : essa non crea mai un oggetto. Si pu migliorare notevolmente le
prestazioni , se oggetti equivalenti vengono richiesti spesso , soprattutto se sono costosi da creare .La
capacit dei metodi statici factory di restituire lo stesso oggetto da ripetere nelle invocazioni consente alle
classi di mantenere uno stretto controllo su quali siano le istanze in qualsiasi momento . Le classi che fanno
questo sono dette istanze controllate. Ci sono diversi motivi per scrivere classi di istanza controllata. Il
Controllo di istanza consente a una classe di garantire che si tratta di un singleton ( item 3) o non-
instantiable ( item 4) . Inoltre, permette una classe immutabile ( item 15 ) utile per rendere la garanzia che
non esistono due istanze uguali.
3) Un terzo vantaggio dei metodi statici factory che, a differenza costruttori , essi possono restituire un
oggetto di qualunque sottotipo del loro tipo di ritorno . Questo vi d grande flessibilit nella scelta della
classe dell'oggetto restituito . Una applicazione di questa flessibilit l' API che pu restituire oggetti senza
che essi faccino le classi pubbliche . Nascondere le classi di implementazione in questo modo porta a una
API molto compatta . Questa tecnica si presta a interfacce based framework. (item 18) , dove le interfacce
forniscono tipi di ritorno naturali per i metodi statici factory .Le interfacce non possono disporre di metodi
statici, cos per convenzione , i metodi statici factory perun'interfaccia denominata Type sono messi in una
classe non-instantiable ( item 4 ) chiamata Types.
4) Un quarto vantaggio di metodi statici factory che riducono il livello di dettaglio per creare istanze di tipi
parametrizzati . Purtroppo , necessario specificare i parametri di tipo quando si richiama il costruttore di
una classe parametrizzata anche se sono evidenti dal contesto . Questo di solito richiede di fornire i
parametri di tipo due volte in rapida successione :
Map<String, List<String>> m =
new HashMap<String, List<String>>();
Lo svantaggio principale di fornire metodi statici factory solo che classi senza costruttori pubblici o
protetti non possono essere sottoclassate . Lo stesso vale per le classi non pubbliche restituite da factories
statiche pubbliche . Per esempio , impossibile sottoclassare qualsiasi delle classi di implementazione
convenienti nel Collection Framework. Probabilmente questo pu essere una benedizione sotto mentite
spoglie , in quanto incoraggia i programmatori ad usare la composizione invece di eredit ( item 16), che
un male. Un secondo inconveniente dei metodi statici factory che essi non sono facilmente distinguibili
da altri metodi statici . Essi non si distinguono, nella documentazione API, nel modo in cui i costruttori lo
fanno e quindi pu essere difficile da capire come creare un'istanza di una classe che fornisce metodi statici
factory invece di costruttori . Lo strumento Javadoc potrebbe un giorno attirare l'attenzione su metodi
statici factory . Intanto , si pu ridurre questo svantaggio , richiamando l'attenzione ai metodi factory statici
in classe o in commenti dinterfaccie , e aderendo alle convenzioni di denominazione comuni .
In sintesi , metodi statici factory e costruttori pubblici entrambe hanno i loro usi , e vale la pena di capire i
loro meriti . Spesso i metodi factory statici sono preferibili, in modo da evitare per riflesso di fornire
costruttori pubblici.
Item 2 - Applicare la propriet Singleton con un costruttore privato
Un singleton semplicemente una classe che viene istanziata esattamente una sola volta. Il Singleton in
genere rappresenta le componenti di un sistema che sono intrinsecamente uniche , come window manager
o il file system. Lesecuzione di una classe singleton pu rendere difficile testare i propri clients , in quanto
impossibile sostituire una implementazione finta per un singleton a meno che implementi un'interfaccia
che sia adatta al suo tipo. Ci sono due modi per implementare singleton. Entrambi sono basati sul
mantenimento del costruttore privato e sull'esportazione di un membro statico pubblico, utile per fornire
un accesso alla sola istanza.
Nel primo approccio, il membro un campo finale :
/ / Singleton con campo finale pubblico
public class Elvis {
public static final Elvis INSTANCE = new Elvis ( ) ;
private Elvis ( ) { ... }
public void leaveTheBuilding ( ) { ... }
}
Il costruttore privato viene chiamato una sola volta , per inizializzare il campo finale public static
Elvis.INSTANCE . La mancanza di un costruttore pubblico o protetto garantisce un ambiente " monoelvistic:
esattamente un'istanza Elvis esister, una sola volta la classe Elvis viene inizializzata - n pi, n meno .
Niente di tutto ci che un clients non pu cambiare, con un avvertimento : un clients privilegiato pu
richiamare il costruttore privato riflessivamente con l' aiuto del metodo AccessibleObject.setAccessible . Se
si necessit di difendersi da questo attacco, modificare il costruttore per fargli gettare un un'eccezione se
chiesto di creare una seconda istanza .
Nel secondo approccio dellattuazione del singleton , il membro pubblico un metodo factory static :
/ / Singleton con la factory statica
public class Elvis {
private static final Elvis INSTANCE = new Elvis ( ) ;
private Elvis ( ) { ... }
public static Elvis getInstance ( ) {return INSTANCE ; }
public void leaveTheBuilding ( ) { ... }
Tutte le chiamate verso Elvis.getInstance restituiscono lo stesso riferimento all'oggetto , e nessun altra
istanza Elvis sar mai creata ( con la stessa avvertenza di cui sopra ) .
Il principale vantaggio dell'approccio campo pubblico (numero 1) che le dichiarazioni fanno si che la
classe un singleton : il campo statico pubblico definitivo , quindi sar sempre limitato allo stesso
riferimento all'oggetto.
Un vantaggio dell'approccio metodo factory che ti d la flessibilit di cambiare idea sul fatto che la classe
dovrebbe essere un singleton senza cambiare la sua API . Il metodo factory restituisce l'unica istanza , ma
potrebbe essere facilmente modificato per tornare indietro. Un secondo vantaggio, riguarda i tipi generici.
Spesso nessuno di questi vantaggi rilevante, e l'approccio campo pubblico pi semplice.
Item 3 - Applicare non-instantiability con un costruttore privato
Di tanto in tanto ti consigliamo di scrivere una classe che solo un raggruppamento di metodi statici e
campi statici . Tali classi hanno acquisito una cattiva reputazione perch alcune persone abusano di loro per
evitare di pensare in termini di oggetti , ma essi hanno usi corretti. Essi possono essere usati per
raggruppare metodi sui valori primitivi o matrici , in mododi java.lang.Math o java.util.Arrays , possono
anche essere utilizzati per creare un gruppo statico dimetodi, o per gli oggetti che implementano una
particolare interfaccia , in maniera di java.util.Collections . Infine , possono essere utilizzati raggruppare i
metodi su una classe finale , invece di estendere la classe . Tali classi di utilit non sono stati progettate per
essere istanziate : un'istanza sarebbe priva di senso . In assenza di costruttori espliciti , tuttavia , il
compilatore fornisce un costuttore pubblico , senza parametri, chiamato costruttore predefinito . Per un
utente, questo costruttore indistinguibile da qualsiasi altro . Il tentativo di imporre non-instantiability
facendo una classe astratta non funziona . La classe pu essere sottoclassata e la sottoclasse instanziata .
Inoltre, ci inganna l'utente facendogli credere la classe stata progettata per l'ereditariet (item 17). Vi ,
tuttavia , un semplice tocco di stile per assicurare non-instantiability . Un costruttore di default viene
generato solo se una classe non contiene esplicitamente costruttori , quindi una classe pu essere fatta
non-instantiable includendo un costruttore privato :
/ / Noninstantiable classe di utilit
public class UtilityClass {
/ / Elimina costruttore predefinito per non-instantiability
Private UtilityClass ( ) {
throw new AssertionError ( ) ;
} ... / / Resto omesso }
Poich il costruttore esplicito privato , inaccessibile al di fuori del classe . LAssertionError non
strettamente necessario , ma fornisce assicurazione in caso il costruttore viene accidentalmente richiamato
dall'interno della classe . Garantisce che la classe non verr mai creata un'istanza in nessun caso . Questo
tocco di classe leggermente contro intuitivo, cos come il costruttore viene fornito espressamente cos
che non pu essere invocato . pertanto consigliabile includere un commento , come mostrato sopra.
Come effetto collaterale, questo trucchetto impedisce anche alla classe di essere sottoclassata. Tutti i
costruttori devono invocare un costruttore della superclasse , esplicitamente o implicitamente , e una
sottoclasse non avrebbe alcun costruttore della superclasse accessibile da richiamare .
Item 4 - Evitare la creazione di oggetti non necessari
Spesso opportuno riutilizzare un singolo oggetto invece di creare un nuovo oggetto equivalente ogni volta
che richiesto. Il riutilizzo pu essere sia pi veloce e pi elegante. Un oggetto pu sempre essere
riutilizzato se immutabile (item 15) . Come esempio estremo di cosa non fare, prendiamo in
considerazione questa dichiarazione :
String s = new String ( " stringette " ) ; / / NON FARE QUESTO !
L'istruzione crea una nuova istanza String ogni volta che viene eseguita, e nessuna di quelle creazioni di
oggetti necessario. L'argomento al costruttore String ( " stringette " ) di per s una istanza String ,
funzionalmente identico a tutte le oggetti creati dal costruttore . Se questo utilizzo si verifica in un ciclo o in
un frequente metodo richiamato, milioni di istanze String possono essere create inutilmente. La versione
migliorata semplicemente il seguente :
String s = " stringette " ;
Questa versione utilizza una singola istanza String , piuttosto che crearne uno nuova ogni volta che viene
eseguita. Inoltre garantito che l'oggetto sar riutilizzata da qualsiasi altro codice in esecuzione nella stessa
macchina virtuale che mantenga la stessa stringa letterale. Spesso possibile evitare di creare oggetti non
necessari utilizzando metodi factory statici (item 1 ), preferendo costruttori di classi immutabili che
forniscono entrambi. Ad esempio, il metodo factory static Boolean.valueOf ( String ) quasi sempre
preferibile alla booleano di costruzione ( String) . Il costruttore crea un nuovo oggetto ogni volta che viene
chiamato, mentre il metodo factory statico non viene mai richiesto a farlo. Oltre al riutilizzo di oggetti
immutabili, anche possibile riutilizzare oggetti mutabili se si sa che non saranno modificati. Qui la
situazione un po pi sottile , e molto pi comune , esempio di cosa non fare . Si tratta di oggetti Date
mutabili che non vengono mai modificati una volta sono stati calcolati i loro valori . Questi modelli di classe
di un persona hanno un metodo isBabyBoomer che dice se la persona un "babyboomer ", in altre parole ,
se la persona nata tra il 1946 e il 1964 :
public class Person {
private final Date birthDate;
// Other fields, methods, and constructor omitted
// DON'T DO THIS!
public boolean isBabyBoomer() {
// Unnecessary allocation of expensive object
Calendar gmtCal =
Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
Date boomStart = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
Date boomEnd = gmtCal.getTime();
return birthDate.compareTo(boomStart) >= 0 &&
birthDate.compareTo(boomEnd) < 0;
}
}
Il metodo isBabyBoomer crea inutilmente un nuovo calendario , fuso orario , e due istanze Data ogni volta
che viene invocato . La versione che segue evita questa inefficienza con un inizializzatore statico :
class Person {
private final Date birthDate;
// Other fields, methods, and constructor omitted
/**
* The starting and ending dates of the baby boom.
*/
private static final Date BOOM_START;
private static final Date BOOM_END;
static {
Calendar gmtCal =
Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.getTime();
}
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0 &&
birthDate.compareTo(BOOM_END) < 0;
}
}
La versione migliorata della classe Person crea calendario , fuso orario , e istanze di data solo una volta ,
quando viene inizializzato , invece di creare loro ogni tempo isBabyBoomer viene richiamato . Ci si traduce
in significativi miglioramenti delle prestazioni se il metodo viene richiamato frequentemente . Non solo
prestazioni migliorate , ma cos lo anche per la chiarezza . La modifica di boomStart e boomEnd da
variabili locali ai campi static final chiaro che queste date sono trattati come costanti , rendendo il codice
pi comprensibile . Il contrappunto a questo articolo item 24 sulla copie difensive. In sintesi item 5
riassume: " Non creare un nuovo oggetto quando si deve riutilizzare uno esistente ", mentre Item 39 dice: "
Non riutilizzare un oggetto esistente quando si deve creare uno nuovo . Nota che la penalit per il riutilizzo
di un oggetto quando la copia difensiva viene chiamata, di gran lunga superiore aella pena di aver
inutilmente creato un oggetto duplicato . Non riuscendo a fare copie difensive dove necessario possono
portare a bug insidiosi e falle di sicurezza , la creazione di oggetti inutili influisce solo su stile e prestazioni .
Item 18 Favor (piacere, favore) classi membri statiche sopra non statiche
Una classe nidificata una classe definita all'interno di un'altra classe. Una classe nidificata dovrebbe
esistere solo per servire la sua classe che la contiene. Se volessi che una classe nidificata fosse utile in
qualche altro contesto, allora dovremmo definire una classe di livello superiore. Ci sono quattro tipi di classi
nidificate:
1) classi membri statiche
2) le classi membri non statiche
3) le classi anonime
4) classi locali
Tutti tranne il primo tipo sono noti come classi interne. Questa voce ti dice quando usare e quale tipo di
classe nidificata e perch. 1) Una classe membro statico il tipo pi semplice di classe nidificata. E meglio
pensare a come succede che una classe normale dichiarata all'interno di un'altra classe e ha l'accesso a
tutti i membri della classe che contiene, anche quelli dichiarati privato. La classe membro statico un
membro statico della classe che la contiene e obbedisce lo stesso alle regole daccessibilit come gli altri
membri statici. Se dichiarata privata, accessibile solo all'interno della classe contenitrice, e cos via.
Sintatticamente, l'unica differenza tra le classi dei membri statici e non statici che le classi membro
statiche hanno il modificatore static nelle loro dichiarazioni. Nonostante la somiglianza sintattica, questi
due tipi di classi nidificate sono molto diversi. 2) Ogni istanza di una classe membro non statico
implicitamente associata ad un istanza della sua classe di appartenenza. Se l'istanza di una classe nidificata
pu esistere in isolamento da un'istanza della sua classe di inclusione , allora la classe nidificata deve essere
una classe membro statico : impossibile creare un'istanza di una classe membro non statico senza
un'istanza che la racchiude . L'associazione tra un istanza di classe membro non statico e la sua inclusione
istanza viene stabilita quando il primo viene creato e non pu essere modificato successivamente.
Normalmente, l'associazione stabilita automaticamente richiamando un costruttore non statico della
classe membro all'interno di un metodo dell'istanza classe. Un uso comune di una classe membro non
statico quello di definire un che permette ad un'istanza della classe esterna di essere vista come un
istanza di una classe indipendente. Per esempio,
// Typical use of a nonstatic member class
public class MySet<E> extends AbstractSet<E> {
... // Bulk of the class omitted
public Iterator<E> iterator() {
return new MyIterator();
}
private class MyIterator implements Iterator<E> {
...
}
Se si dichiara una classe membro che non richiede l'accesso ad una istanza racchiusa, sempre dovrai metter
il modificatore static nella sua dichiarazione, rendendolo un statico piuttosto che una classe membro non
statico . Se si omette questo modificatore, ogni istanza dovr avere un riferimento estraneo alla sua istanza
inclusa. Un uso comune delle classi membro statiche private quello di rappresentare i componenti
delloggetto rappresentato dalla loro classe di inclusione. 3) Classi anonime sono differenti a qualsiasi altra
cosa nel linguaggio di programmazione Java. Come ci si aspetterebbe, una classe anonima non ha nome.
Non un membro della sua classe contenitrice . Piuttosto deve essere dichiarata insieme ad altri membri ,
contemporaneamente dichiarata e istanziata al punto di utilizzo . Le classi anonime sono ammesse in
qualsiasi punto del codice in cui l'espressione legale. Le classi anonime hanno istanze incluse se e solo se
si verificano in un contesto non statico. Ma se si verificano in un contesto statico, non possono avere
membri statici. Ci sono molte limitazioni all'applicabilit classi anonime. Non si possono istanziare tranne
nel punto che stanno dichiarate. Non possibile eseguire test instanceof o fare qualsiasi altra cosa che
richiede di denominare la classe. Non possibile dichiarare una classe anonima per implementare
interfacce multiple , o per estendere una classe e implementare un'interfaccia allo stesso tempo . I clients
di una classe anonima non possono invocare nessun membro ad eccezione di quelli da cui si eredita il suo
supertipo. Un uso comune delle classi anonime quello di creare oggetti funzionali (item 21 ) al volo. 4) Le
classi locali sono le meno utilizzate di frequente delle quattro tipi di classi nidificate. La classe locale pu
essere dichiarata ovunque, una variabile locale pu essere dichiarata e obbedisce al stesse regole. Classi
locali hanno attributi in comune con ciascuno degli altri tipi di classi nidificate. Come classi membro, hanno
nomi e possono essere utilizzate ripetutamente. Come classi anonime, racchiudono istanze solo se sono
definite in un contesto non statico, e non possono contenere membri statici ed inoltre come classi
anonime, dovrebbero essere brevi in modo da non danneggiare la leggibilit. Per ricapitolare, ci sono
quattro diversi tipi di classi nidificate, e ciascuno ha la sua particolarit. Se una classe nidificata deve essere
visibile dall'esterno di un singolo metodo o troppo lunga per adattarsi all'interno di un metodo, utilizzare
una classe membro. Se ogni istanza della classe membro ha bisogno di un riferimento alla sua istanza
inclusa, la rendo non statica, altrimenti la rendo statica. Supponendo che la classe appartiene all'interno di
un metodo, se necessario creare istanze di una sola posizione e c' un tipo preesistente che caratterizza la
classe allora la rendo una classe anonima, in caso contrario faccio un classe locale.
Item 22 - Sostituire i puntatori a funzione con le classi e interfacce (non presente nel libro solo slide)
C supporta i puntatori a funzione, tipicamente utilizzato per consentire al chiamante di una funzione di
specializzarsi nel suo comportamento passando un puntatore ad una seconda funzione, talvolta indicata
come un callback. Ad esempio l'operazione va ripetuta nella visita di un elenco, il comparatore passato a
quick sort. Tutto ci risulta una sorta di modello di strategia. Java raggiunge la stessa funzionalit
utilizzando il linguaggio degli oggetti funzionali. Oggetti i cui metodi eseguono operazioni su altri oggetti,
passati esplicitamente
class StringLengthComparator {
public int compare(String s1, String s2) {return
s1.length() - s2.length();}
La classe StringLengthComparator stateless. Pu essere utile un singleton per risparmiare sui costi di
creazione di oggetti inutili (Item 2,4)
class StringLengthComparator {
private StringLengthComparator() { } // private
constructor
public static final StringLengthComparator INSTANCE = //
static final factory
new StringLengthComparator();
Tutto questo pu essere utilizzato in un modello di strategia vera e propria. Definisci uninterfaccia( la
strategia del Abstract)
public interface Comparator {public int compare(Object o1,
Object o2); }
Sia StringLengthComparator una possibile implementazione del comparatore (uno dei tanti possibili
ConcreteStrategy)
class StringLengthComparator implements Comparator{
private StringLengthComparator() { } // private
constructor
public static final StringLengthComparator INSTANCE = //
static final factory
new StringLengthComparator();
public int compare(String s1, String s2) {return
s1.length() - s2.length();}
Le classi Concrete strategy sono spesso dichiarate utilizzando le classi anonime (Item 18)
// a statement invokes Arrays.sort passing the
reference to an array of String
// and the constructor of an implementation of
Comparator
// that is defined as a nested local anonymous class
// that defines the implementation for the
Comparator.compare method
Arrays.sort(stringArray, new Comparator() {
// anonymous class local to the constructor invokation
// sets up the concrete strategy for comparison
public int compare(Object o1, Object o2) {
String s1 = (String)o1;
String s2 = (String)o2;
return s1.length() -
s2.length();}
}); // end of the local anonymous class, and of the
Capitolo 7 Metodi in questo capitolo vengono illustrati diversi aspetti del metodo di progettazione: come
trattare parametri e valori di ritorno, come progettare le firme dei metodi , e come fornire la
documentazione dei metodi. Come gli altri capitoli, questo capitolo si concentra sulla facilit d'uso,
robustezza, e flessibilit.
Item 23 - Parametri di controllo per la validit
La maggior parte dei metodi e costruttori hanno alcune restrizioni su valori i quali possono essere passati
nei loro parametri. Ad esempio, non raro che i valori di indice deve essere non negativo e riferimenti a
oggetti devono essere non nullo . Si dovrebbe chiaramente documentare tutte le restrizioni e farle
rispettare con controlli all'inizio del il corpo del metodo. Questo un caso particolare del principio generale
che si dovrebbe tentare di rilevare gli errori il pi veloce dopo che si verifichino. Se un valore di un
parametro non valido viene passato ad un metodo e il metodo verifica i suoi parametri prima
dell'esecuzione, fallir e creer un appropriata eccezione. Se il metodo non riesce a controllare i suoi
parametri, possono accadere molte cose. Il metodo potrebbe fallire con un'eccezione errata, peggio
ancora, il metodo potrebbe funzionare normalmente, ma calcolare il risultato sbagliato. Peggio di tutto , il
metodo potrebbe funzionare normalmente ma lasciare qualche oggetto in uno stato compromesso,
causando un errori.
Per i metodi pubblici , utilizzare il Javadoc @throw tag per documentare l'eccezione che sar generata se
una restrizione sui valori dei parametri viene violata tipicamente leccezione sar IllegalArgumentException
e/o IndexOutOfBounds. Un esempio tipico :
/**
* Returns a BigInteger whose value is (this mod m). This method
* differs from the remainder method in that it always returns a
* non-negative BigInteger.
*
* @param m the modulus, which must be positive
* @return this mod m
* @throws ArithmeticException if m is less than or equal to 0
*/
public BigInteger mod(BigInteger m) {
if (m.signum() <= 0)
throw new ArithmeticException("Modulus <= 0: " + m);
... // Do the computation
Per i metodi pubblici verificare la validit necessario fino al chiamato. Per il package privato, potrebbe
anche essere una responsabilit del chiamante.
E ' particolarmente importante verificare la validit dei parametri che non sono utilizzati da un metodo, ma
sono conservati per un uso successivo . Ad esempio, si consideri il metodo factory statico, che prende un
array int e restituisce un elenco vista della matrice. Se un client di questo metodo dovesse passare nullo, il
metodo getterebbe una NullPointerException,. A quel punto, l'origine dell'istanza LIst potrebbe essere
difficile da determinare, potrebbe complicare notevolmente il compito di debugging . Costruttori
rappresentano un caso particolare del principio che si dovrebbe utilizzare per verificare la validit dei
parametri che devono essere riutilizzati per un uso successivo. critico verificare la validit dei parametri
del costruttore per impedire la costruzione di un oggetto che viola le sue invarianti di classe . Ci sono
eccezioni alla regola che si dovrebbe verificare i parametri di un metodo prima di eseguire il suo calcolo .
Un'importante eccezione il caso in cui il controllo di validit sarebbe costoso e poco pratico e viene
eseguito il controllo di validit implicitamente nel processo da fare per il calcolo. Ad esempio, si consideri
un metodo che ordina un elenco di oggetti, come Collections.sort ( List ) . Tutte gli oggetti nella lista devono
essere reciprocamente comparabili. Nel processo di ordinamento dell'elenco, ogni oggetto nella lista sar
confrontato con qualche altro oggetto nella lista. Se l'oggetti non sono simili tra loro, uno di questi
confronti getter una Class- CastException , che esattamente ci che il metodo di ordinamento dovrebbe
fare pertanto sarebbe inutile controllare in anticipo che gli elementi nella lista erano comparabili tra di loro.
Per riassumere, ogni volta che si scrive un metodo o un costruttore , si dovrebbe pensare in merito a ci
che esiste sulle restrizioni dei suoi parametri . Si dovrebbe documentare queste restrizioni e ad applicarle
con controlli espliciti all'inizio del corpo del metodo. E' importante prendere l'abitudine di fare questo. Il
semplice lavoro che essa comporta sar ripagato la prima volta che un controllo di validit non riesce.
Item 24 - Creare copie difensive in caso di necessit
Una cosa che rende Java piacevole da usare che si tratta di un linguaggio sicuro. Questo significa che, in
assenza di metodi nativi immune da sovraccarichi del buffer , superamenti di matrice, puntatori selvatici,
e altri errori di corruzione della memoria che affliggono pericolosamente linguaggi come C e C + + . In un
linguaggio sicuro, possibile scrivere classi e sapere con certezza che i loro invarianti rimarranno veri, non
importa cosa accade in qualsiasi altra parte del sistema. Anche in un linguaggio sicuro non sei isolato dalle
altre classi senza che tu non faccia alcuna accortezza. necessario programmare difensivamente, con il
presupposto che i clients della classe faranno del loro meglio per distruggere i tuoi invarianti. Questo pu
effettivamente essere vero se qualcuno cerca di rompere la sicurezza del sistema, ma pi probabilmente
limplementazione delle nostre classi dovranno fare i conti con un comportamento imprevisto derivante da
errori onesti da parte dei programmatori che utilizzano la nostra API. In entrambi i casi, vale la pena di
prendere il tempo di scrivere classi che siano robuste per far fronte ai client mal educati :-)
A prima vista, questa classe pu sembrare immutabile e fa rispettare linvariante. Si tratta, tuttavia, di
violare facilmente questa invariante sfruttando il fatto che la Date mutevole:
// Attack the internals of a Period instance
Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
end.setYear(78); // Modifies internals of p!
Per proteggere l'interno di un'istanza Period da questo tipo di attacco, essenziale fare una copia difensiva
di ciascun parametro mutevole al costruttore e utilizzare le copie come componenti dell'istanza Period al
posto del originali:
// Repaired constructor - makes defensive copies of parameters
public Period(Date start, Date end) {
this.start = new Date(start.getTime());
this.end = new Date(end.getTime());
if (this.start.compareTo(this.end) > 0)
throw new IllegalArgumentException(start +" after "+ end);
Con il nuovo costrutto, il precedente attacco non avr alcun effetto sull'istanza Period. Si noti che le copie
difensive sono fatte prima di controllare la validit dei parametri e il controllo di validit viene eseguito
sulle copie piuttosto che sugli originali. Mentre questo pu sembrare innaturale, necessario. Protegge la
classe contro modifiche ai parametri da parte di un altro thread durante la "finestra di vulnerabilit",
periodo nel quale i parametri sono controllati e il momento in cui vengono copiati. Si noti, inoltre, che non
abbiamo usato il metodo clone di Date per fare le copie difensive, perch Date non-final, il metodo clone
non garantito per restituire un oggetto la cui classe java.util.Date: potrebbe restituire una sottoclasse
non attendibile specificamente progettata per furberie. Tale sottoclasse potrebbe, per esempio, registrare
un riferimento per ogni istanza in un elenco statico privato al momento della sua creazione e consentire al
malintenzionato di accedere a questa lista. Ci darebbe all'attaccante libero utilizzo su tutte le istanze. Per
evitare questo tipo di attacco, non utilizzare il clone metodo per fare una copia di difesa di un parametro il
cui tipo sottoclassato da parte di soggetti non attendibili.
// Second attack on the internals of a Period instance
Date start = new Date();
Date end = new Date();
Period p = new Period(start, end);
p.end().setYear(78); // Modifies internals of p!
Per difendersi contro il secondo attacco, basta semplicemente modificare le funzioni di accesso per tornare
ad copie difensive di campi interni modificabili:
// Repaired accessors - make defensive copies of internal fields
public Date start() {
return new Date(start.getTime());
}
public Date end() {
return new Date(end.getTime());
}
Con il nuovo costruttore e le nuove funzioni di accesso, Period veramente immutabile. Non importa
quanto dannoso o incompetente sia un programmatore, non vi semplicemente alcun modo di violare
l'invariante. Questo vero perch non c' alcun modo per qualsiasi classe diversa da Period di guadagnare
l'accesso a uno dei campi modificabili in un'istanza Period. Questi campi sono veramente incapsulati
all'interno dell'oggetto. Le copie difensive dei parametri non sono solo per le classi immutabili. Le copie
difensive possono avere una riduzione delle prestazioni ad esse associate e non sempre giustificato. Se
una classe si fida di suo chiamante che non modifica un componente interno, allora pu essere opportuno
scartare le copie difensive. In sintesi, se una classe ha componenti mutevoli che si ottengono da o di
ritorno da i suoi client, la classe deve copiare difensivamente questi componenti. Se il costo del copia fosse
proibitivo e la classe si fida dei suoi client, che non modificano le componenti impropriamente, la copia
difensiva pu essere sostituita da documentazione.
Item 5,12,13,14,15,16 + intro
il valore tra parentesi accanto al n dell'item indica il n corrispondente sul libro.
Introduzione
Gli idiomi (di cui fanno parte gli Item che andremo a studiare) sono regole che
contengono pratiche generalmente usate dai programmatori. Sono soluzioni ricorrenti
per comuni problemi di programmazione. Mentre i Design Pattern sono di alto livello
e indipendenti dal linguaggio, gli idiomi sono pattern di basso livello per linguaggi
specifici. Durante il design si usano Pattern, durante l'implementazione si usano gli
idiomi poich forniscono una pi specifica soluzione.
Item 5 (6): Eliminare riferimenti obsoleti a oggetti
Ci sono puntatori (tipo quando faccio POP nello Stack) che rimangono in vita anche
se non li posso pi usare. In casi come questo utile (e a volte necessario) forzare
l'utilizzo del Garbage Collector per evitare spreco di memoria. Le perdite di memoria
in lingue dotate di Garbage Collector (pi propriamente note come trattenute non
intenzionali di oggetti) sono insidiose. Se un riferimento a un oggetto viene
inavvertitamente mantenuto, non solo escluso dalla raccolta dei rifiuti quell'oggetto,
ma lo sono anche tutti gli oggetti a cui fa riferimento tale oggetto, e cos via. Anche
se solo pochi riferimenti agli oggetti vengono involontariamente conservati, a molti
oggetti pu essere impedito di essere ripuliti dal GC, con potenziali grandi effetti
sulle prestazioni. La soluzione semplice e si basa sull'evitare la ritenzione
involontaria di un oggetto annullando riferimenti fuori uso: cio quando so che non
dovr pi usare un oggetto pongo il suo riferimento a Null. Quando i programmatori
vengono a contatto per la prima volta con questo problema, possono compensare
annullando ogni riferimento a un oggetto non appena il programma ha finito di
usarlo. Questo non n necessario n auspicabile, in quanto ingombra il programma
inutilmente! Questa pratica, infatti, dovrebbe essere l'eccezione e non la norma, essa
risulta necessaria in 3 casi:
1. ogni volta che una classe gestisce la propria memoria;
2. nella gestione della cache, una volta messo un riferimento a un oggetto in una
cache, facile dimenticare che l e lasciarlo nella cache molto tempo dopo
l'essere diventato irrilevante;
3. quando si ha a che fare con ascoltatori e callback,se si implementa una API in
cui i clienti registrano le callback, ma non annullare la registrazione
esplicitamente, si accumuleranno a meno che non si prende qualche
precauzione: il modo migliore per garantire che i callback siano rifiuti raccolti
prontamente quello di memorizzarli solo tramite riferimenti deboli (weak
pointer).
L'esempio dello Stack sopra citato rientra nel primo caso.
Poich le perdite di memoria tipicamente non manifestano fallimenti evidenti,
possono rimanere presenti in un sistema per anni. Esse sono tipicamente scoperte solo
a seguito di un'attenta ispezione del codice o con l'ausilio di uno strumento di debug
noto come heap profiler. Pertanto, molto desiderabile l'imparare ad anticipare i
problemi di questo tipo prima che si verifichino e impedire che accada.
Item 12(13): Ridurre al minimo l'accessibilit delle classi e dei membri
Un modulo ben progettato nasconde tutti i suoi dettagli implementativi, separando
nettamente la sua API dalla sua implementazione. Questo concetto, noto come
Information hiding o incapsulamento, serve per produrre disaccoppiamento:
1. Facilita lo sviluppo in parallelo e la manutenzione, poich rende il codice pi
facile da leggere. Inoltre permette di aumentare le performance potendo
lavorare sui moduli che creano problemi senza intaccare la correttezza degli
altri;
2. Rende il SW pi riutilizzabile: non essendo i moduli molto legati a ci che li
circonda si possono rivelare utili anche in altre circostanze;
3. Mitiga il rischio di costruire grandi sistemi (singoli moduli possono rivelarsi di
successo, anche se il sistema per cui sono stati costruiti non lo ).
La regola semplice: rendere ogni classe o membro il pi inaccessibile possibile. In
altre parole, utilizzare il livello di accesso pi basso possibile coerente con il corretto
funzionamento del software che si sta scrivendo. Il controllo degli accessi un
importante strumento per l'information hiding.
Per il top-level di classi e interfacce, ci sono solo due possibili livelli di accesso:
package-private o public.
1. Package-private: si rendono parte della realizzazione e si pu modificare,
sostituire o eliminare in una versione successiva senza timore di danneggiare i
client esistenti.
2. Public: si obbligati a sostenerlo per sempre per mantenere la compatibilit.
Per i membri (campi, metodi, classi annidate e interfacce annidate) ci sono quattro
possibili livelli di accesso:
1. Privato: Il membro accessibile solo dalla classe di primo livello in cui
dichiarata.
2. Pacchetto-privato: Il membro accessibile da qualsiasi classe nel pacchetto in
cui dichiarata. Tecnicamente noto come accesso predefinito, questo il
livello di accesso che si ottiene se non viene specificato alcun modificatore di
accesso.
3. Protetto: Il membro accessibile da sottoclassi della classe in cui dichiarata e
da ogni classe del pacchetto in cui dichiarata.
4. Pubblico: Il membro accessibile da qualsiasi luogo
Se un metodo esegue l'override di un metodo della super-classe, non gli permesso di
avere un livello di accesso pi basso nella sottoclasse di quanto non faccia nella
super-classe. Ci necessario per garantire che un'istanza della sottoclasse
utilizzabile ovunque sia utilizzabile un'istanza della superclasse. Se si violano questa
regola il compilatore genera un messaggio di errore quando si tenta di compilare la
sottoclasse. Nessuna variabile dovrebbe mai essere pubblica: si usano i metodi getter
e setter per accedervi in modo controllato. Classi con campi modificabili pubblici non
sono thread-safe. Anche se un campo final e si riferisce ad un oggetto immutabile,
rendendo il campo pubblico si d la flessibilit per passare ad una nuova
rappresentazione interna dei dati in cui il campo non esiste.
Per riassumere, si dovrebbe sempre ridurre l'accessibilit, per quanto possibile.
Dopo aver progettato con cura una API pubblica minimale, si dovrebbe evitare a ogni
classe, interfaccia o membro di diventare una parte della API. Con l'eccezione dei
campi finali statici pubblici, le classi pubbliche non dovrebbero avere campi pubblici.
Assicurarsi che gli oggetti referenziati da campi finali statici pubblici siano
immutabili.
Item 13(15): Favorire immutabilit (minimizzare mutabilit)
Una classe immutabile semplicemente una classe le cui istanze non possono essere
modificate. Ci sono molte buone ragioni per questo: le classi immutabili sono pi
facili da progettare, implementare e usare di classi mutevoli. Esse sono meno inclini a
errori e sono pi sicure. Inoltre gli oggetti immutabili possono essere condivisi
liberamente in quanto non richiedono la sincronizzazione. Gli oggetti dovrebbero
essere fatti il pi possibile immutabili. Oggetti immutabili una volta istanziati non
cambiano. Per fare una classe immutabile vanno seguite 5 regole:
1. non esporre metodi che modifichino lo stato dell'oggetto, questo impedisce a
sottoclassi imprudenti o malintenzionate di compromettere il comportamento
immutabile della classe comportandosi come se lo stato dell'oggetto fosse
cambiato;
2. assicurarsi che la classe non possa essere estesa;
3. porre tutti i campi final, ci esprime chiaramente l'intenzione in un modo che
viene applicato dal sistema;
4. porre tutti i campi private, questo impedisce ai client di ottenere l'accesso agli
oggetti mutabili riferiti dai campi e di modificare direttamente questi oggetti;
5. assicurarsi accesso esclusivo ad ogni componente mutabile.
L'approccio funzionale potrebbe apparire innaturale se non si ha familiarit con esso,
ma consente l'immutabilit, che ha molti vantaggi. Oggetti immutabili sono semplici.
Un oggetto immutabile pu trovarsi in un solo stato, lo stato in cui stato creato. Se
si sicuri che tutti i costruttori stabiliscono invarianti di classe, allora garantito che
questi invarianti rimarranno veri per tutto il tempo, senza ulteriore sforzo da parte
vostra o da parte del programmatore che utilizza la classe. Oggetti mutabili, d'altro
canto, possono contenere stati arbitrariamente complessi. Se la documentazione non
fornisce una descrizione precisa delle transizioni di stato effettuate con metodi
mutatori, pu essere difficile o impossibile utilizzare una classe mutevole affidabile.
Una classe immutabile pu essere rilassata permettendo mutevole un campo che non
influenza il comportamento esterno. L'unico vero svantaggio di classi immutabili
che richiedono un oggetto separato per ogni valore distinto. Se una classe non pu
essere fatta immutabile, bisogna limitare la sua mutabilit il pi possibile. Pertanto,
fare ogni campo final a meno che non vi sia un motivo valido per farlo non-final.
Item 14(16): Preferire la composizione all'eredit
Implementare l'ereditariet un buon modo per rendere un codice riutilizzabile.
Infatti, oltre ad andare a braccetto con l'Open-Close Principle, l'ereditariet sicura
all'interno dello stesso package e quando si eredit classi appositamente studiate per
essere estese. Per l'ereditariet pu creare non pochi problemi, in particolare si pu
avere:
1. violazione dell'incapsulamento, una sottoclasse dipende dai dettagli
implementativi della superclasse per il suo corretto funzionamento;
2. pericoloso ereditare da classi concrete al di fuori del proprio package;
3. classe base fragile;
4. internal not documented detail: classe base e derivata possono essere fatte
bene, ma non specificando alcuni dettagli si possono creare conflitti
problematici.
L'eredit si porta dietro delle rigidit. Infatti una classe base, per acquisire nuovi
metodi nelle successive versioni deve soddisfare pi requisiti: se la classe base
cambia devono poterlo fare anche i suoi legami e una sottoclasse deve evolvere di
pari passo con la sua super-classe. Per evitare alcuni problemi si potrebbe pensare che
sia sicuro estendere una classe se si limita l'aggiunta di nuovi metodi e ci si astiene
dal fare override di quelli esistenti. Questo tipo di estensione molto pi sicuro, non
priva di rischi. Per fortuna c' un modo per evitare tutti i problemi visti: invece di
estendere una classe esistente si pu dare alla nuova classe un campo privato che fa
riferimento a un'istanza della classe esistente. Questa tecnica chiamata
composizione poich la classe esistente diventa una componente di quella nuova.
Ogni metodo istanza nella nuova classe richiama il metodo corrispondente sulla
istanza contenuta della classe esistente e restituisce i risultati. Questo noto come
forwarding, e i metodi della nuova classe sono noti come metodi di inoltro. La classe
risultante sar solida, senza dipendenze sui dettagli di implementazione della classe
esistente. Anche l'aggiunta di nuovi metodi per la classe esistente non avr alcun
impatto sulla nuova classe. Un metodo pratico per i9mplementare la composizione
creare una classe wrapper: la nuova classe incapsula quella esistente.
Anche questi ultimi metodi presentano piccoli problemi, detti Self problem: l'oggetto
avvolto non conosce del suo involucro, in uno schema di callback esso passa un
riferimento a se stesso, eludendo il wrapper; Non adatto per l'uso in callback
framework, in cui gli oggetti passano riferimenti a se stessi ad altri oggetti per
invocazioni successive (framework: codice gi scritto che lascia dei punti di
estensione i quali saranno poi definiti nel caso concreto. Pu essere visto come
complementare alle librerie, si ha un meccanismo di inversione del controllo). Inoltre
si ha un leggero impatto sulle prestazioni nell'uso di forwarding e wrapper, di solito
non un problema. un po' noioso per scrivere i metodi di forwarding, parzialmente
compensato dal fatto che si deve scrivere solo un costruttore.
L'ereditariet appropriata solo quando la sottoclasse davvero un sottotipo sella
superclasse! Se si usa ereditariet dove sarebbe appropriata la composizione si
espone inutilmente dettagli di implementazione.
Per riassumere, l'ereditariet potente, ma problematico perch viola
l'incapsulamento. opportuno solo quando esiste un vero e proprio rapporto di
sottotipo tra la sottoclasse e superclasse. Anche allora, l'ereditariet pu portare a
fragilit se la sottoclasse in un pacchetto differente dalla superclasse e la
superclasse non progettato per ereditariet. Per evitare questa fragilit, utilizzare la
composizione e forwarding invece di eredit, soprattutto se esiste un'interfaccia
appropriata per attuare una classe wrapper. Non solo sono classi wrapper pi robuste
di sottoclassi, ma sono anche pi potenti.
N.B. Il problema discusso in questo item non si applica alla estensione di interfacce.
Item 15(17): Progettazione e documenti per eredit o altrimenti vietarla
Per fare ereditariet necessario fare le classi base robuste e documentare come fare
ad ereditarle. Ogni classe deve documentare con precisione gli effetti dell'override su
qualsiasi metodo:
1. documentare il self-use di metodi sottoponibili a override: quali metodi sovra
scrivibili (non finali) si invoca, in quale sequenza, e come i risultati di ogni
invocazione influenzano la successiva lavorazione.
2. documentare di eventuali circostanze in cui potrebbe invocare un metodo
sottoponibile a override (ad esempio, le invocazioni di thread in background o
inizializzatori statici).
Per convenzione un metodo che che ne invoca un altro sovra scrivibile contiene una
descrizione di questa invocazione alla fine del suo commento documentativo. La
descrizione di un metodo che richiama metodi sovra scrivibili inizia con "Questa
implementazione" (This implementation), in modo da sottolineare che il
comportamento documentato pu risentire di override.
Esempio: in java.util.AbstractCollection, per public boolean remove(Object o)
Removes a single instance of the specified element from this collection, if it is present (optional
operation). More formally, removes an element e such that (o==null ? e==null : o.equals(e)), if the
collection contains one or more such elements. Returns true if the collection contained the specified
element (or equivalently, if the collection changed as a result of the call).
This implementation iterates over the collection looking for the specified element. If it finds the
element, it removes the element from the collection using the iterator's remove method. Note that
this implementation throws an UnsupportedOperationException if the iterator returned by this
collection's iterator method does not implement the remove method
Non lascia alcun dubbio che l'override del metodo iteratore influenzer il
comportamento di rimozione, e descrive esattamente come il comportamento
dell'Iterator restituito dal metodo iteratore influenzer il comportamento del metodo
remove. Si noti che, poich l'incapsulamento viene violato, la documentazione viola il
principio secondo il quale una buona la documentazione API descrive quello che un
determinato metodo fa e non come lo fa. Per consentire ai programmatori di scrivere
sottoclassi efficienti senza eccessivi problemi, una classe pu fornire ganci al suo
funzionamento interno, sotto forma di metodi protetti giudiziosamente scelti o, in rari
casi, di campi protetti. Quali metodi devono essere esposti come protetti? Ogni
metodo protetto rappresenta un impegno a un dettaglio implementativo. Ma, un
metodo protetto mancante pu rendere una classe inutilizzabile per l'eredit. Non si
hanno proiettili magici (soluzioni perfette).
L'unico modo per testare una classe progettata per l'ereditariet scrivere sottoclassi.
Se si omette un membro protetto cruciale, cercaredi scrivere una sottoclasse render
l'omissione ovvia. Al contrario, se diverse sottoclassi sono scritte e nessuna utilizza
un membro protetto, probabilmente si dovrebbe renderlo privato. L'esperienza
dimostra che tre sottoclassi sono in genere sufficienti per testare una classe
estensibile. Una o pi di queste sottoclassi dovrebbe essere scritta da una persona
diversa dall'autore superclasse. necessario testare la propria classe scrivendo
sottoclassi prima di rilasciarla.
Ci sono un paio di restrizioni a cui una classe deve obbedire per consentire
l'ereditariet. I costruttori non devono invocare metodi sottoponibili a override,
direttamente o indirettamente: Il costruttore della superclasse viene eseguito prima
del costruttore della sottoclasse; il metodo prevalente sar invocato prima che il
costruttore della sottoclasse sia eseguito, se il metodo sovrascritto dipende da una
qualsiasi inizializzazione eseguita dal costruttore della sottoclasse, allora il metodo
non si comporter come previsto.
Esempio:
public class Super {
public Super() {m(); }
public void m() {}
}
final class Sub extends Super {
private final ate date; !! "lan# final, set b$
constructor
Sub() {date % ne& ate();}
public void m() {S$stem.out.println(date);}
public static void main(Strin'() ar's) {Sub s %
ne& Sub(); s.m(); }
}
il metodo "m" viene richiamato dal costruttore "Super()" prima che il costruttore
"Sub()" sia eseguito.
La progettazione di una classe per eredit pone dei limiti sostanziali sulla classe.
Questa non una decisione da prendere con leggerezza. Ci sono alcune situazioni in
cui chiaramente la cosa giusta da fare, come ad esempio le classi astratte, incluse le
implementazioni di interfacce (item 18). Ci sono altre situazioni in cui chiaramente
la cosa sbagliata da fare, come le classi immutabili (item 15). La soluzione migliore a
questo problema di vietare sottoclassi in classi che non sono state progettate e
documentate per essere sottoclassate in modo sicuro. Si pu fare in 2 modi:
dichiarare la classe finale oppure fare tutti i costruttori private o package-private e
aggiungere static factories pubblicche.
Se una classe concreta non implementa un'interfaccia standard, allora si pu creare
disagi ad alcuni programmatori vietando eredit. Se ritieni che necessario
consentire l'ereditariet da una classe, un approccio ragionevole quello di garantire
che la classe non richiama uno dei suoi metodi sottoponibili a override e per
documentare questo fatto. In altre parole, eliminare il self-use della classe di metodi
sottoponibili a override completamente. In tal modo, si creer una classe che
ragionevolmente sicura nei confronti della sottoclasse. Sovrascrivere un metodo non
potr mai influenzare il comportamento di qualsiasi altro metodo.
possibile eliminare il self-use di una classe di metodi sottoponibili a override
meccanicamente, senza modificare il suo comportamento. Spostare il corpo di
ciascun metodo sottoponibile a override ad un "metodo di supporto" privato e dfar s
che ogni metodo sottoponibile ad override richiama il suo metodo di supporto
privato. Poi sostituire ogni self-use di un metodo sottoponibile a override con una
invocazione diretta del metodo di supporto privato del metodo sottoponibile a
override.
Item 16(18): Preferire interfacce alle classi astratte
Interfacce e classi astratte sono molto simili. La differenza pi evidente tra i due
meccanismi che le classi astratte sono autorizzati a contenere le implementazioni di
alcuni metodi, mentre le interfacce no. In linea di principio si preferisce le interfacce:
1. Le classi astratte sono autorizzate a contenere le implementazioni di alcuni
metodi, ma, per implementare una classe astratta, una classe deve ereditare da
essa (e Java permette solo l'ereditariet singola). Mentre una classe che
implementa l'interfaccia pu essere ovunque nella gerarchia delle classi.
2. Classi esistenti possono essere facilmente adattate a implementare una nuova
interfaccia mentre non possono, in generale, essere adattate per estendere una
nuova classe astratta. (Se due classi devono implementare la stessa classe
astratta, questo dovrebbe essere collocato in alto nella gerarchia dei tipi in
modo da essere un antenato comune e tutti i discendenti intermedi dovrebbero
implementare la nuova classe astratta pure).
3. Le interfacce sono ideali per fare mixin: un mixin un tipo che una classe pu
implementare in aggiunta alla sua "tipo primario" per dichiarare che fornisce
un certo comportamento facoltativo. Ad esempio Comparable un'interfaccia
mixin che consente a una classe di dichiarare che le sue istanze sono ordinate
rispetto ad altri oggetti tra loro comparabili. Le classi astratte non possono
essere utilizzati per definire mixins a causa dell'ereditariet singola.
4. Le interfacce permettono la costruzione di strutture di tipo non gerarchiche,
molti concetti non rientrano ordinatamente in una gerarchia rigida.
5. Le interfacce consentono wrapper class idiom (item 14) per migliorare le
funzionalit. Utilizzando le classi astratte per definire i tipi, il programmatore
non pu scegliere la composizione invece che l'eredit.
possibile combinare le virt di interfacce e classi astratte, fornendo lo scheletro
implementativo di una classe stratta per le interfacce esportate: superando cos
l'inconveniente delle interfacce, che non possono fornire un'implementazione
parziale. Per convenzione, chiamare AbstractInterface lo scheletro implementativo
delle interfacce (ad esempio AbstractCollection, AbstractSet, AbstractList ).
Tecnica per simulare l'ereditariet multipla: la classe che implementa l'interfaccia
inoltra invocazioni di metodi di interfaccia a un'istanza contenuta di una classe
interna privata che estende lo scheletro implementativo. Strettamente legato al
wrapper class idiom, fornisce la maggior parte dei benefici di ereditariet multipla,
evitando le insidie.
Utilizzo di classi astratte per definire i tipi che consentono molteplici
implementazioni ha un grande vantaggio rispetto all'utilizzo di interfacce: molto pi
facile far evolvere una classe astratta di un'interfaccia. Se, in una versione successiva,
si desidera aggiungere un nuovo metodo di una classe astratta, sempre possibile
aggiungere un metodo concreto contenente un'implementazione predefinita
ragionevole. Tutte le implementazioni esistenti della classe astratta forniranno quindi
il nuovo metodo. Questo non funziona per le interfacce: se viene aggiunto un nuovo
metodo di un'interfaccia, tutte le implementazioni devono essere estese. Mentre se
viene aggiunto a una classe astratta, pu essere fornita qualche implementazione di
default. In tal modo, le classi astratte sono pi flessibili delle interfacce che devono
essere progettate con cura in modo da non avere bisogno di riaprirle. Infatti una volta
rilasciato ed implementato un interfaccia quasi impossibile cambiarla.
Per riassumere, l'interfaccia generalmente il modo migliore per definire un tipo
che consente pi implementazioni. Un'eccezione a questa regola il caso in cui la
facilit di evoluzione ritenuta pi importante di flessibilit e potenza. In queste
circostanze, necessario utilizzare una classe astratta per definire il tipo, ma solo se
si capisce e si pu accettare le limitazioni. Se si esporta un interfaccia non banale, si
dovrebbe prendere in seria considerazione il fornire una implementazione scheletrica
con essa. Infine, necessario progettare tutte le interfacce pubbliche con la massima
cura e testare a fondo scrivendo implementazioni multiple.
Abstract Factory (C)
Intento: Presenta uninterfaccia per la creazione di famiglie di prodotti, in modo tale che il cliente che gli
utilizza non abbia conoscenza delle loro concrete classi. Questo consente:
- Assicurarsi che il cliente crei soltanto prodotti vincolati fra di loro.
- Lutilizzo di diverse famiglie di prodotti da parte dello stesso cliente.
Motivazione: esempio widget factory che produce diversi tipi di widget, che sono composti da
window,scroolbar ecc. il client usa solo astrazioni.
Applicabilit: Il pattern AbstractFactory si basa sulla creazione di interfacce per ogni tipo di prodotto. Ci
saranno poi concreti prodotti che implementano queste interfacce, stesse che consentiranno ai clienti di
fare uso dei prodotti. Le famiglie di prodotti saranno create da un oggetto noto come factory. Ogni famiglia
avr una particolare factoryche sar utilizzata dal Cliente per creare le istanze dei prodotti. Siccome non si
vuole legare al Cliente un tipo specifico di factoryda utilizzare, le factoryimplementeranno una interfaccia
comune che sar dalla conoscenza del Cliente.
Struttura:

Partecipanti:
AbstractFactory: Dichiara una interfaccia per le operazioni che creano e restituiscono i prodotti. Nella
dichiarazione di ogni metodo, i prodotti restituiti sono dei tipi AbstractProduct.
ConcreteFactory: Implementa lAbstractFactory, fornendo le operazioni che creano e restituiscono oggetti
corrispondenti a prodotti specifici (ConcreteProduct).
AbstractProduct: Dichiarano le operazioni che caratterizzano i diversi tipi generici di prodotti.
ConcreteProduct: Definiscono i prodotti creati da ogni ConcreteFactory.
Client: Utilizza lAbstractFactory per rivolgersi alla ConcreteFactory di una famiglia di prodotti. Utilizza i prodotti
tramite la loro interfaccia AbstractProduct.
Conseguenze: isola le classi concrete. Abbiamo che labstract factory senza stato. Facile cambiare il tipo
famiglia oggetto creato, basta cambiare il concrete factory usato. +) abbiamo consistenza tra i prodotti da
usare insieme, gli raggruppiamo in famiglie. - ) Ogni nuovo tipo di prodotto implica di rifare tutte le factory
Osservazioni: Dovuto al fatto che n lAbstractFactory n gli AbstractProduct implementano operazioni, in
Java diventa pi adeguato codificarli come interfacce piuttosto che come classi astratte.

Builder (C)
Intento: Separa la costruzione di un oggetto complesso dalla sua rappresentazione, in modo che lo stesso
processo di costruzione consenta la creazione di diverse rappresentazioni.
Motivazione: Si tratta di un pattern creazionale basato su oggetti e viene utilizzato per creare un oggetto
senza doverne conoscere i suoi dettagli implementativi. Questo pattern consente di utilizzare un Client che
non debba essere a conoscenza dei passi necessari al fine della creazione di un oggetto ma tali passaggi
vengono delegati ad un Director che sa cosa e come fare.
Applicabilit: Il Builder pattern propone di separare la logica del processo di costruzione dalla
costruzione stessa. Per fare ci si utilizza un oggetto Director, che determina la logica di costruzione del
prodotto, e che invia le istruzioni necessarie ad un oggetto Builder, incaricato della sua realizzazione.
Siccome i prodotti da realizzare sono di diversa natura, ci saranno Builder particolari per ogni tipo di
prodotto, ma soltanto un unico Director, che nel processo di costruzione invocher i metodi del Builder
scelto secondo il tipo di prodotto desiderato (i Builder dovranno implementare uninterfaccia comune per
consentire al Director di interagire con tutti questi). Potrebbe capitare che per ottenere un prodotto
particolare alcune tappe del processo di costruzione non debbano essere considerate da alcuni Builder (ad
esempio, il Builder che costruisce i modelli non orientati, deve trascurare il nome della relazione e il grado
della partecipazione minima).
Struttura:

Partecipanti:
Builder: Dichiara una interfaccia per le operazioni che creano le parti delloggetto Product. Implementa il
comportamento default per ogni operazione.
ConcreteBuilder: Forniscono le operazioni concrete dellinterfaccia corrispondente al Builder. Costruiscono e
assemblano le parti del Product. Forniscono un metodo per restituire il Product creato.
Director: Costruisce il Product invocando i metodi dellinterfaccia del Builder.

Product: Rappresenta loggetto complesso in costruzione. I ConcreteBuilders costruiscono la
rappresentazione interna del Product. Include classi che definiscono le parti costituenti del Product.

Conseguenze: consente di cambiare la rappresentazione interna del prodotto: il Builder non conosce la
rappresentazione interna del prodotto che pu essere cambiata semplicemente costruendo un nuovo
Builder.
isolamento tra Builder: ogni Builder indipendente dallaltro pertanto possibile aumentare la modularit.
controllo accurato del processo di creazione: la creazione avviene step-by-step e questo consente di stabilire
passo dopo passo cosa effettuare.
Osservazioni: La classe astratta Builder dichiara il metodo getModel che i ConcreteBuilders devono
implementare, con il codice necessario per restituire ogni particolare tipo Product. Il tipo di ritorno del
metodo getModel indicato come Object, dato che a priori non si ha conoscenza della specifica tipologia di
Product. In questo modo si abilita la possibilit di restituire qualunque tipo doggetto (perch tutte le classi
Java, in modo diretto o indiretto, sono sottoclassi di Object). Si fa notare che il method overloading di Java
non consente modificare la dichiarazione del tipo di valore di ritorno di un metodo di una sottoclasse,
motivo per il quale i ConcreteBuilders devono anche dichiarare Object come valore di ritorno, nei propri
metodi getModel.
Factory Method (C)
Intento: Definisce uninterfaccia per creare oggetti, ma lascia alle sottoclassi la decisione del tipo di classe a
istanziare.
Motivazione: Framework deve poter creare diversi documenti ma non sa il tipo concreto quindi uso il factory
Applicabilit: una classe non pu anticipare classi concrete da creare oppure vuole che subclassi decidendo
cosa creare. Le classi delegano la responsabilit a subclassi e vogliono localizzare di chi delegato. Il pattern
Factory Method suggerisce il portare via dal framework la creazione di ogni particolare tipo di Elemento.
Per fare ci, verr delegato alle sottoclassi dello Strumento, che specializzano le funzioni di gestione di ogni
tipo di Elemento, il compito di creare le particolari istanze di classi che siano necessarie.
Stuttura:

Partecipanti
Product: Definisce linterfaccia di tutti gli elementi da utilizzare nellapplicazione.
ConcreteProduct: Implementano i concreti prodotti.
Creator: Dichiara il factory method che restituisce un oggetto della classe Product. Richiama il factory
method per creare i Product.
ConcreteCreator: Redefine il factory method per restituire una istanza di ConcreteProduct.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
rappresenta un gancio alle sotto-classi: tramite il Creator possibile scegliere quale classe concreta utilizzare
e decidere di cambiarla senza avere nessun impatto verso il Client
consente di collegare gerarchie di classi in modo parallelo: i ConcreteCreator possono collegarsi con i
ConcreteProduct e generare un collegamento parallelo tra gerarchie diverse.
Osservazioni: Si vuole rendere noto che il factory method (newElement) dichiara come tipo da restituire al
punto di chiamata, sia nel Creator (ElementHandler), sia in ogni ConcreteCreator (PlaceHandler e
ConnectorHandler), un oggetto di tipo Product (MapElement), invece dei particolari tipi da produrre (Place e
Connector). Questo dovuto al fatto che le sottoclassi che redefiniscono un metodo devono esplicitare
lo stesso tipo di ritorno che quello indicato nella dichiarazione del metodo nella superclasse.
Adapter (S)
Intento: Specifica i tipi di oggetti a creare, utilizzando unistanza prototipo, e crea nuove istanze tramite la
copia di questo prototipo.
Motivazione: Si tratta di un pattern strutturale basato su classi o su oggetti in quanto possibile ottenere
entrambe le rappresentazioni. Viene utilizzato quando si intende utilizzare un componente software ma
occorre adattare la sua interfaccia per motivi di integrazione con lapplicazione esistente. Questo comporta
la definizione di una nuova interfaccia che deve essere compatibile con quella esistente in modo tale da
consentire la comunicazione con linterfaccia da adattare. Come abbiamo accennato, tale pattern pu
essere basato sia su classi che su oggetti pertanto linstanza della classe da adattare pu derivare da
ereditariet oppure da associazione.
Applicabilit: LAdapter pattern offre due soluzioni possibili, denominate Class Adapter e Object Adapter,
che si spiegano di seguito:
- Class Adapter: la classe esistente si estende in una sottoclasse che implementa la desiderata
interfaccia. I metodi della sottoclasse mappano le loro operazioni in richieste ai metodi e attributi della classe
di base.
- Object Adapter: si crea una nuova classe che implementa linterfaccia richiesta, e che
possiede al suo interno unistanza della classe a riutilizzare. Le operazioni della nuova classe fanno
invocazioni ai metodi delloggetto interno.
Struttura:
Per il class adapter

Per Object Adapter

Partecipanti
TargetInterface: Specifica linterfaccia che il Client utilizza.
Client: Comunica con loggetto interessato tramite la TargetInterface.
Adaptee: Implementa una interfaccia che deve essere adattata.
Adapter: Adatta linterfaccia dellAdaptee verso la TargetInterface.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
Class Adapter: prevede un rapporto di ereditariet tra Adapter e Adaptee, in cui Adapter specializza Adaptee,
pertanto non possibile creare un Adapter che specializzi pi Adaptee. Se esiste una gerarchia di Adaptee
occorre creare una gereachia di Adapter.
Object Adapter : prevede un rapporto di associazione tra Adapter e Adaptee, in cui Adapter instanzia
Adaptee, pertanto possible avere un Adapter associato con pi Adaptee.
Osservazioni: La strategia di costruire un Class Adapter possibile soltanto se lAdaptee non stato
dichiarato come final class.
Bridge (S)
Intento: Separa unastrazione dalla sua implementazione, in modo che entrambe possano variare
indipendentemente.
Motivazione: Si tratta di un pattern strutturale basato su oggetti che viene utilizzato per disaccoppiare dei
componeti software. In questo modo possibile effettuare uno switch a Run-Time, garantire il
disaccoppiamento, nascondere limplementazione, estendere la specializzazione delle classi.
Applicabilit: Il Bridge pattern suggerisce la separazione dellastrazione dallimplementazione, in gerarchie
diverse, legando oggetti della seconda a quelli della prima, tramite un relazione di conmposizione.
Struttura:

Partecipanti
Abstraction: Specifica linterfaccia dellastrazione. Gestisce un riferimento ad un oggetto Implementor.
RefinedAbstraction: Implementano linterfaccia definita dallAbstraction.
Implementor: Specifica linterfaccia definita per le classi di implementazione.
ConcreteImplementor: Implementano linterfaccia Implementor.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
disaccoppia linterfaccia dallimplementazione: disaccoppiando Abstraction e Implementor possibile gestire
i cambiamenti delle classi concrete senza cablare nel codice dei riferiementi diretti
migliora lestendibilit: possibile estendere la gerarchia di Abstraction e Implementor senza problemi
nasconde limplementazione al client: il Client non si deve porre il problema di conoscere limplementazione
delle classi concrete.
Composite (S-B)
Intento: Consente la costruzione di gerarchie di oggetti composti. Gli oggetti composti possono essere
conformati da oggetti singoli, oppure da altri oggetti composti. Questo pattern utile nei casi in cui si vuole:
- Rappresentare gerarchie di oggetti tutto-parte.
- Essere in grado di ignorare le differenze tra oggetti singoli e oggetti composti.
Motivazione: Si tratta di un pattern strutturale basato su oggetti che viene utilizzato quando si ha la
necessit di realizzare una gerarchia di oggetti in cui loggetto contenitore pu detenere oggetti elementari
e/o oggetti contenitori. Lobiettivo di permettere al Client che deve navigare la gerarchia, di comportarsi
sempre nello stesso modo sia verso gli oggetti elementari e sia verso gli oggetti contenitori.
Applicabilit: Il pattern Composite definisce la classe astratta componente che deve essere estesa in due
sottoclassi: una che rappresenta i singoli componenti, e unaltra che rappresenta i componenti composti, e
che si implementa come contenitore di componenti. Il fatto che questultima sia un contenitore di
componenti, li consente di immagazzinare al suo interno, sia componenti singoli, sia altri contenitori (dato
che entrambi sono stati dichiarati come sottoclassi di componenti).
Struttura:

Partecipanti
Component: Dichiara una interfaccia comune per oggetti singoli e composti. Implementa le operazioni di
default o comuni tutte le classi.
Leaf: Estende la classe Component, per rapperesentare gli oggetti che non sono composti (foglie).
Implementa le operazioni per questi oggetti.
Composite: Estende la classe Component, per rappresentare gli oggetti che sono composti.Immagazzina al
suo interno i propri componenti. Implementa le operazioni proprie degli oggetti composti, e
particolarmente quelle che riguardano la gestione dei propri componenti.
Client: in questo esempio sar il programma principale quello che far le veci di cliente. Utilizza gli oggetti
singoli e composti tramite linterfaccia rappresentata dalla classe astratta Component.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
Definisce la gerarchia: Gli oggetti della gerarchia possono essere composti da oggetti semplici e/o da oggetti
contenitori che a loro volta sono composti ricorsivamente da altri oggetti semplici e/o da oggetti contenitori .
Semplifica il client: il Client tratta gli oggetti semplici e gli oggetti contenitori nello stesso modo. Questo
semplifica il suo lavoro il quale astrae dalla specifica implementazione.
Semplifica la modifica dellalbero gerarchico: lalberatura facilmente modificabile
aggiungendo/rimuovendo foglie e contenitori.
Decorator (S-B)
Intento: Aggiunge dinamicamente responsabilit addizionali ad un oggetto. In questo modo si possono
estendere le funzionalit doggetti particolari senza coinvolgere complete classi.
Motivazione: Si tratta di un pattern strutturale basato su oggetti che viene utilizzato per aggiungere a
RunTime delle funzionalit ad un oggetto. In Java, e pi in generale nella programmazione ad oggetti, per
aggiungere delle funzionalit ad una classe viene utilizzata lereditariet che prevede la creazione di classi
figlie che specializzano il comportamento della classe padre ma tutto ci avviene a CompileTime. Pertanto se
in sede di definizione della struttura delle classi non vengono previste delle specifiche funzionalit, queste
non saranno disponibili a RunTime. Al fine di superare questo limite, attraverso la decorazione possibile
aggiungere nuove funzionalit senza dover alterare la struttura delle classi ed i rapporti di parentela in
quanto possibile agire a RunTime per modificare il comportamento di un oggetto.
Applicabilit: Il pattern suggerisce la creazione di wrapper classes (Decorator) che racchiudono gli oggetti
ai quali si vuole aggiungere le nuove responsabilit. Questi ultimi oggetti, insieme ai Decorator devono
implementare una interfaccia comune, in modo che lapplicazione possa continuare ad interagire con gli
oggetti decorati. Per una stessa interfaccia possono esserci pi Decorator, ad esempio, per investire i ruoli di
capoufficio e di responsabile di un progetto. Il fatto che Decorator e oggetti decorati implementino la stessa
interfaccia, consente anche lapplicazione di un Decorator ad un altro oggetto gi decorato, ottenendo in
questo modo la sovrapposizione di funzioni (ad esempio, un impiegato potrebbe essere investito come
capoufficio e responsabile di un progetto contemporaneamente).
Struttura:

Partecipanti
Component: Specifica linterfaccia degli oggetti che possono avere delle responsabilit aggiunte
dinamicamente.
ConcreteComponent: Implementa loggetto in cui si possono aggiungere nuove responsabilit.
Decorator: Possiede un riferimento alloggetto Component e specifica una interfaccia concordante con
linterfaccia Component.
ConcreteDecorator: Aggiunge nuove responsabilit al Component.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
maggiore flessibilit rispetto alla eredit: permette di aggiungere funzionalit in modo molto pi semplice
rispetto allereditariet
funzionalit solo se richieste: consente di aggiungere delle funzionalit solo se occorrono realmente senza
ereditare una struttura di classi che prevede un insieme di funzionalit di cui se ne utilizzeranno olo una
parte. Nel caso in cui tali funzionalit sono anche a pagamento, consente di scegliere solo quelle
strettamente necessarie da acquistare, coprendo esigenze di budget.
aumento di micro-funzionalit: la presenza di molte classi Decorator di cui ognuna di esse aggiunge una
micro funzionalit, pu creare problemi in fase di comprensione o di debug del codice.
Facade (S)
Intento: Fornisce una interfaccia unificata per un insieme di interfacce di un sottosistema, rendendo pi
facile luso di questultimo.
Motivazione: Si tratta di un pattern strutturale basato su oggetti che viene utilizzato per nascondere la
complessit del sistema e ridurre la comunicazione e la dipendenza del Client. Lutilizzo di questo pattern
prevede di esporre una interfaccia per linvocazione di un Sistema tale da semplificare linvocazione ad opera
del Client.
Applicabilit: Il Facade pattern suggerisce la creazione di un oggetto che presentia uninterfaccia
semplificata al cliente, ma in grado di gestire tutta la complessit delle interazioni tra gli oggetti delle diverse
classi per compiere lobbiettivo desiderato.
Struttura:



Partecipanti:
Facade: Ha conoscenza delle funzionalit di ogni classe del sottosistema. Delega agli appropriati
oggetti del sottosistema ogni richiesta pervenuta dallesterno.
Subsystem classes: Implementano le funzionalit del sottosistema. Gestiscono le attivit assegnate dal
Facade. Non hanno riferimenti verso il Facade.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
riduce il numero di associazioni: disaccoppiando il Client dal Sistema possibile ridurre il numero di
associazioni effettuate tra questi 2 attori, riducendo le interazioni.
agevola il cambiamento : il basso accoppiamento rende possibile le modifiche al Sistema senza dover
modificare anche il Client.
non esclude luso diretto del Sistema : il Client pu comunque utilizzare direttamente il Sistema se lo ritiene
necessario. Lesistenza del Facade non esclude la possibilit di farlo: sempre che sappia come fare.
Proxy (S-B)
Intento: Fornisce una rappresentazione di un oggetto di accesso difficile o che richiede un tempo importante
per laccesso o creazione. Il Proxy consente di posticipare laccesso o creazione al momento in cui sia
davvero richiesto
Motivazione: Si tratta di un pattern strutturale basato su oggetti che viene utilizzato per accedere ad un un
oggetto complesso tramite un oggetto semplice.
Questo pattern pu risultare utile se loggetto complesso: richiede molte risorse computazionali. richiede
molto tempo per caricarsi. locato su una macchina remota e il traffico di rete determina latenze ed
overhead. non definisce delle policy di sicurezze e consente un accesso indiscriminato. non viene mantenuto
in cache ma viene rigenerato ad ogni richiesta. In tutti questi casi possibile disposte delle politiche di
gestione e/o di ottimizzazione. A seconda del contesto, viene aggiunto un prefisso per descrivere il caso di
riferimento:
Virtual Proxy Pattern: ritarda la creazione e linizializzazione delloggetto poich richiede grosse risorse (es:
caricamento immagini )
Remote Proxy Pattern: fornisce una rappresentazione locale delloggetto remoto (es: accesso ad oggetto
remoto tramite RMI )
Protection Proxy Pattern: fornisce un controllo sullaccesso delloggetto remoto (es: richiesta
username/password per laccesso)
Smart Proxy Pattern: fornisce una ottimizzazione delloggetto (es: caricamento in memoria delloggetto)
Il proxy espone gli stessi metodi delloggetto complesso che maschera e questo permette di adattare
facilmente loggetto senza richiedere modifiche.
Applicabilit: l Proxy pattern suggerisce limplemetazione di una classe (ProxyFileHandler) che offra la stesa
interfaccia della classe originale (FileHandler), e che sia in grado di risolvere le richieste pi semplici
pervenute dallapplicativo, senza dover utilizzare inutilmente le risorse (ad esempio, restituire il nome del
file). Solo al momento di ricevere una richiesta pi complessa (ad esempio, restituire il testo del file), il
proxy andrebbe a creare il vero FileHandler per inoltrare a esso le richieste. In questo modo gli oggetti pi
pesanti sono creati solo al momento di essere necessari. Il proxy che serve a questa finalit spesso viene
chiamato virtual proxy.






Struttura:

Partecipanti:
Proxy: Mantiene un riferimento per accedere al RealSubject. Implementa una interfaccia identica a quella del
RealSubject, in modo che pu sostituire a esso. Controlla lacceso al RealSubject, essendo responsabile della
sua istanziazione e gestione di riferimenti. Come virtual proxy pospone la istanziazione del RealSubject,
tramite la gestione di alcune informazioni di questo.
Subject: Fornisce linterfaccia comune per il RealSubject e il Proxy, in modo che questo ultimo possa essere
utilizzato in ogni luogo dove si aspetta un RealSubject.
RealSubject: Implementa loggetto vero e proprio che il RealSubject rappresenta.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
un Proxy Remoto: nasconde il fatto che un oggetto appartiene ad un diverso spazio di indirizzamento
un Proxy Virtuale: ottimizza la creazione di un oggetto solo nel momento in cui realmente necessario
un Protection Proxy ed uno Smart Proxy: aggiungono ulteriori comportamenti quando si accede ad un
oggetto
Chain of Responsibilty (B)
Intento: Consente di separare il mittente di una richiesta dal destinatario, in modo di consentire a pi di un
oggetto di gestire la richiesta. Gli oggetti destinatari vengono messi in catena, e la richiesta trasmessa dentro
questa catena fino a trovare un oggetto che la gestisca.
Motivazione: Si tratta di un pattern comportamentale basato su oggetti e viene utilizzato quando si ha la
necessit di disaccoppiare il mittente di una richiesta dal destinatario. Nel caso in cui il destinatario preveda
che le richieste debbano essere gestite da una serie di attori ognuno dei quali con diversa responsabilit e tra
loro collegati in modo gerarchico, siamo in presenza di una catena di responsabilit. A fronte della ricezione
di una richiesta, il destinatario gestir la risposta propagando la richiesta nella catena fino ad individuare il
responsabile. La gerarchia solitamente parte dal generale al particolare pertanto una richiesta destinata
allultimo elemento della catena verr propagata verso lalto fino a raggiungere lincaricato responsabile che
avr il compito di gestire/eseguire lazione richiesta. Il mittente non tenuto a conoscere chi materialmente
dovr gestire/eseguire la richiesta, lunica cosa che dovr sapere a chi dovr inviare la richiesta. Sar cura
del destinatario organizzarsi in modo efficiente per recuperare il responsabile. Pensiamo per esempio ad un
call-center che deve gestire le richieste delle proprie utenze, qualora il personale non in grado di risolvere il
problema, propaga la richiesta al servizio di secondo livello che prover a gestire/risolvere il problema
altrimenti propaga a sua volta il problema. In Java la propagazione delle eccezioni un esempio di catena di
responsabilit. Quando si verifica un errore, il gestore dellerrore, se non riesce a gestire leccezione in corso,
propaga lerrore nella catena.
Applicabilit: Il Chain of responsibility pattern propone la costruzione di una catena di oggetti responsabili
della gestione delle richieste pervenute dai clienti. Quando un oggetto della catena riceve una richiesta,
analizza se corrisponde a lui gestirla, o, altrimenti, inoltrarla al seguente oggetto dentro la catena. In questo
modo, gli oggetti che iniziano la richiesta devono soltanto interfacciarsi con loggetto pi basso della catena
di responsabilit.
Struttura:

Partecipanti
Handler: Specifica una interfaccia per la gestione delle richieste. In modo opzionale, implementa un
riferimento a un oggetto successore.
ConcreteHandler: Gestiscono le richieste che corrispondono alla propria responsabilit. Accedono ad
un successore (se possibile), nel caso in cui la richiesta non corrisponda alla propria gestione.
Client: inoltra una richiesta a un ConcreteHandler della catena.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
riduce laccoppiamento: il richiedente deve solo sapere che la propria richiesta verr gestita
adeguatamente, non ha bisogno di sapere chi sar realmente a gestire la richiesta.
aggiungere flessibilit nellassegnazione delle responsabilit degli oggetti: la catena della responsabilit pu
essere modificata senza condizionare il richiedente.
risposta non garantita: la richiesta viene presa in carico e propagata nella gerarchia ma potrebbe non
individuare il responsabile e non riuscire a dare una risposta. Oppure se la gerarchia delle responsabilit
errata, la richiesta non viene gestita.
Osservazioni: Un altro approccio nellutilizzo di questo design pattern pu osservarsi nella nel meccanismo di
Java per la gestione delle eccezioni: ogni volta che viene sollevata una eccezione, questa pu essere
gestita nello stesso metodo in cui si presenta (tramite le istruzioni trycatch), oppure essere lanciata
verso il metodo precedente nello stack di chiamate. A sua volta, questo metodo potrebbe gestire leccezione
oppure continuare a lanciarlo al successivo. Finalmente, se il metodo main non gestisce leccezione, la Java
Virtual Machine ne tiene cura di esso interrompendo lesecuzione del programma e stampando le
informazioni riguardanti leccezione.

Iterator (B)
Intento: Fornisce un modo di accedere sequenzialmente agli oggetti presenti in una collezione, senza esporre
la rappresentazione interna di questa.
Motivazione: Si tratta di un pattern comportamentale basato su oggetti e viene utilizzato quando, dato un
aggregato di oggetti, si vuole accedere ai suoi elementi senza dover esporre la sua struttura. Lobiettivo di
questo pattern quello di disaccoppiare lutilizzatore e limplementatore dellaggregazione di dati, tramite
un oggetto intermedio che esponga sempre gli stessi metodi indipendentemente dallaggregato di dati. E
costituito da 3 soggetti: lUtilizzatore dei dati, lIteratore che intermedia i dati e lAggregatore che detiene i
dati secondo una propria logica.
Applicabilit: Il pattern Iterator suggerisce limplementazione di un oggetto che consenta lacceso e
percorso della collezione, e che fornisca una interfaccia standard verso chi interessato a percorrerla e ad
accede agli elementi.
Struttura:

Partecipanti:
Iterator: Specifica linterfaccia per accedere e percorrere la collezione.
ConcreteIterator: Implementa la citata interfaccia. Tiene traccia della posizione corrente allinterno
della collezione.
Aggregate: specifica una interfaccia per la creazione di oggetti Iterator.
ConcreteAggregate: Crea e restituisce una istanza di iterator.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
unica interfaccia di accesso: laccesso ai dati avviene tramite lIterator che espone ununica interfaccia e
nasconde le diverse implementazioni degli Aggregator
diversi iteratori di accesso: lAggregator pu essere attraversato tramite diversi Iterator in cui ogni Iterator
nasconde un algoritmo diverso
Osservazioni: In una situazione di acceso concorrente ad una collezione, diventa necessario fornire adeguati
meccanismi di sincronizzazione per literazione su di essa, come si spiega nel Java Tutorial.
Mediator (B)
Intento: Definisce un oggetto che incapsula il modo di interagire di un gruppo doggetti, consentendo il
disaccoppiamento tra questi, in forma tale di poter variare facilmente le interazioni fra di loro.
Motivazione: Si tratta di un pattern comportamentale basato su oggetti e viene utilizzato per permettere lo
scambio di messaggi tra diversi attori tramite un intermediario. In questo modo gli attori sono collegati
indirettamente tramite un intermediario. Disaccoppiare gli attori consente di gestire meglio una serie di
problematiche come: centralizzazione delle connessioni, modifiche pi rapide, semplificazione dei protocolli.
Nel gergo del pattern Mediator usiamo il termine Colleghi per indicare gli attori.
Applicabilit: Questo pattern propone la creazione di incapsulare il comportamento collettivo delle diversi
classi componeti il sistema (colleagues), tramite una classe separata denominata Mediator. Il Mediator
diventa lagente dintermediazione tra i diversi oggetti, i quali soltanto devono interfacciarsi con
esso, riducendo il numero di interconnessioni.
Struttura:

Partecipanti
Mediator: Specifica una interfaccia per la comunicazione da parte dei Colleagues.
ConcreteMediator: Implementa il comportamento cooperativo tramite la coordinazione dei
Colleagues. Possiede riferimenti verso i Colleagues.
Colleague: Possiede un riferimento al Mediator. Implementa un metodo di notifica di eventi al Mediator.
ConcreteColleague: Comunica gli eventi al Mediator invece di comunicarli ad altri Colleagues.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
Disaccoppiare i colleghi: i colleghi dialogano tra di loro iin modo indiretto passando per il Mediatore e questo
facilita la gestione delle comunicazioni
Semplificare le connessioni: il Mediatore consente di ridurre le connessioni dei Colleghi da many-to-many a
one-to-many
Controllo centralizzato: il controllo delle comunicazioni centralizzato e questo consente di avere una
visione complessiva del sistema ed una gestione pi efficente delle modifiche
Single Point of Failure: nel caso di malfunzionamento del Mediatore lintero sistema sar coinvolto ed in caso
di fermo del Mediatore, i Colleghi resteranno isolati
Osservazioni: Dato che il Mediator dichiara ma non implementa operazioni, questo viene specificato come
una interfaccia in Java.


Observer (B)
Intento: Consente la definizione di associazioni di dipendenza di molti oggetti verso di uno, in modo che se
questultimo cambia il suo stato, tutti gli altri sono notificati e aggiornati automaticamente.
Motivazione: Si tratta di un pattern comportamentale basato su oggetti che viene utilizzato quando si vuole
realizzare una dipendenza uno-a-molti in cui il cambiamento di stato di un soggetto venga notificato a tutti i
soggetti che si sono mostrati interessati.
Applicabilit: Il pattern Observer assegna alloggetto monitorato (Subject) il ruolo di registrare ai suoi
interni un riferimento agli altri oggetti che devono essere avvisati (ConcreteObservers) degli eventi del
Subject, e notificarli tramite linvocazione a un loro metodo, presente nella interfaccia che devono
implementare (Observer).
Struttura:

Partecipanti
Subject: Ha conoscenza dei propri Observer, i quali possono esserci in numero illimitato. Fornisce operazioni
per laddizione e cancellazione di oggetti Observer. Fornisce operazioni per la notifica agli Observer.
Observer: Specifica una interfaccia per la notifica di eventi agli oggetti interessati in un Subject.
ConcreteSubject: Possiede uno stato dellinteresse dei ConcreteSubject. Invoca le operazioni di notifica
ereditate dal Subject, quando devono essere informati i ConcreteObserver.
ConcreteObserver: Implementa loperazione di aggiornamento dellObserver.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
Astratto accoppiamento tra Subject e Observer: il Subject sa che una lista di Observer sono interessati al suo
stato ma non conosce le classi concrete degli Observer, pertanto non vi un accoppiamento forte tra di loro.
Notifica diffusa: il Subject deve notificare a tutti gli Observer il proprio cambio di stato, gli Observer sono
responsabili di aggiungersi e rimuoversi dalla lista.
Strategy (B)
Intento: Consente la definizione di una famiglia dalgoritmi, incapsula ognuno e gli fa intercambiabili fra di
loro. Questo permette modificare gli algoritmi in modo indipendente dai clienti che fanno uso di essi.
Motivazione: Si tratta di un pattern comportamentale basato su oggetti e viene utilizzato per definire una
famiglia di algoritmi, incapsularli e renderli intercambiabili. Il client definisce lalgoritmo da utilizzare,
incapsulandolo in un contesto, il quale verr utilizzato nella fase di elaborazione. Il contesto detiene i
puntamenti alle informazioni necessarie al fine della elaborazione, cio dati e funzione: solita equazione
y=f(x)!
Applicabilit: Lo Strategy pattern suggerisce lincapsulazione della logica di ogni particolare algoritmo, in
apposite classi (ConcreteStrategy) che implementano linterfaccia che consente agli oggetti MyArray
(Context) di interagire con loro. Questa interfaccia deve fornire un accesso efficiente ai dati del Context,
richiesti da ogni ConcreteStrategy, e viceversa.
Struttura:

Partecipanti
Strategy: Dichiara una interfaccia comune per tutti gli algoritmi supportati. Il Context utilizza questa
interfaccia per invocare gli algoritmi definiti in ogni ConcreteStrategy.
ConcreteStrategy: Implementano gli algoritmi che usano la interfaccia Strategy
Context: Viene configurato con un oggetto ConcreteStrategy e mantiene un riferimento verso esso. Pu
specificare una interfaccia che consenta alle Strategy accedere ai propri dati.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
Unalternativa allereditariet: possibile estendere il Context per specializzare il suo comportamento ma si
rischia di legare troppo il Context con lo Strategy
Le strategie eliminano i blocchi condizionali: le strategie consentono di eliminare i blocchi condizionali che
determinano il comportamento voluto.
Collaborazione tra Strategy e Context dispendiosa: le strategie possono richiedere maggiori o minori
informazioni di contesto di quello disponibili dal Context pertanto occorre definire una modalit di scambio
informazioni efficiente tra Context e Strategy. Un modo per evitare loverloading dei metodi nelle classi di
Strategy per ricevere parametri diversi, di inserire i parametri nel Context per poi passarlo alla classe
Strategy.
Visitor (B)
Intento: Rappresenta una operazione da essere eseguita in una collezione di elementi di una struttura.
Loperazione pu essere modificata senza alterare le classi degli elementi dove opera.
Motivazione: Si tratta di un pattern comportamentale basato su oggetti e viene utilizzato per eseguire delle
operazioni sugli elementi di una struttura. Lutilizzo di questo pattern consente di definire le operazioni di un
elemento senza doverlo modificare.
Applicabilit: La soluzione consiste nella creazione di un oggetto (ConcreteVisitor), che in grado di
percorrere la collezione, e di applicare un metodo proprio su ogni oggetto (Element) visitato nella collezione
(avendo un riferimento a questi ultimi come parametro). Per agire in questo modo bisogna fare in modo che
ogni oggetto della collezione aderisca ad uninterfaccia (Visitable), che consente al ConcreteVisitor di essere
accettato da parte di ogni Element. Poi il Visitor, analizzando il tipo di oggetto ricevuto, fa linvocazione alla
particolare operazione che in ogni caso si deve eseguire.
Struttura:

Partecipanti
Visitor: Specifica le operazioni di visita per ogni classe di ConcreteElement.
ConcreteVisitor: Specifica le operazioni di visita per ogni classe di ConcreteElement. La firma di ogni
operazione identifica la classe che spedisce la richiesta di visita al ConcreteVisitor, e in questo modo il visitor
determina la concreta classe da visitare. Finalmente il ConcreteVisitor accede agli elementi direttamente
tramite la sua interfaccia.
Element: Dichiara loperazione accept che riceve un riferimento a un Visitor come argomento.
ConcreteElement: Implementa linterfaccia Element.
ObjectStructure: Offre la possibilit di accettare la visita dei suoi componenti.
Conseguenze: Tale pattern presenta i seguenti vantaggi/svantaggi:
Facilit nellaggiungere nuovi Visitor: definendo un nuovo Visitor sar possibile aggiungere una nuova
operazione ad un Element
Difficolt nellaggiungere nuovi Element: definire un nuovo Element comporter la modifica dellinterfaccia
Visitor e di tutte le implementazioni
Separazione tra stato ed algoritmi: gli algoritmi di elaborazioni sono nascosti nelle classi Visitor e non
vengono esposti nelle classi Element.
Iterazione su struttura eterogenea: la classe Visitor in grado di accedere a tipi diversi, senza la necessit
che tra di essi ci sia un vincolo di parentela. In poche parole, il metodo visit() pu definire come parametro
un tipo X oppure un tipo Y senza che tra di essi ci sia alcuna relazione di parentela, diretta o indiretta.
Accumulazione dello stato: un Visitor pu accumulare delle informazioni di stato a seguito
dellattraversamento degli Element.
Violazione dellincapsulamento: i Visitor devono poter accedere allo stato degli Element e questo pu
comportare la violazione dellincapsulamento.
Una libreria: un insieme di funzioni che possibile chiamare, al giorno doggi solitamente organizzata in
classi. Ogni chiamata fa un certo lavoro e restituisce il controllo al client.
Un Framework: rappresenta un certo disegno astratto, con pi comportamenti integrati. Per utilizzarlo,
inserisci le tue metodologie nei vari luoghi del framework sia per sottoclassarlo, sia per inserirlo nelle tue
classi. Il codice del framework chiama poi il codice in questi punti.
Una caratteristica importante di un framework che i modi definiti dall'utente , che permettono di
adattare un framework, saranno spesso ri-chiamati allinterno dello stesso framework, piuttosto che dal
codice dell'applicazione utente. Il framework gioca spesso il ruolo del programma principale nel
coordinamento e nel sequenziamento dellattivit dell'applicazione. Questa inversione di controllo
conferisce al framework il potere per funzionare come estensibile di scheletri.( Nel senso scheletri di
implementazioni). I metodi forniti dallutente personalizzano i generici algoritmi definiti nel framework per
una particolare applicazione. " (Ralph Johnson e Brian Foote)
NB: Linversione di controllo un fenomeno comune che si incontra quando si estende i framework. Infatti
spesso inteso come una caratteristica distintiva di un framework. "
Il passaggio dalle librerie ai framework molto interessante per quanto riguarda il fenomeno
dellinversione di controllo nel ambito di chi-chiama-chi contro chi-riusa-chi.
a) nuovo codice invoca oggetti riutilizzati di una libreria (Inversione di controllo)
b) nuovo codice viene invocato dagli oggetti, in un framework riutilizzato (principio di Hollywood)
NB: Nellingegneria del software, il principio di Hollywood indicato come "non ci chiamare, ti chiameremo
noi."

Adattatori pluggable: Si consideri un framework che fornisce un'implementazione astratta di responsabilit
applicabile ad una variet di tipi. Esempio: avvolgere un payload all'interno di un involucro, inviare
linvolucro, involucro di che cosa?






Il framework pu predisporre l'installazione di un adattatore per facilitare listanziazione vera e propria. Si
noti che qui l'adattatore progettato in anticipo, non come aggiornamento. Vi sono 2 schemi:
1) Abstract Operations
2) Delegate Objects.
Abstract Operations: si divide in
FrameworkClass: parte del framework, definisce una virtuale ristretta interfaccia: un insieme minimo di
metodi che possono assumersi tutte le responsabilit che dipendono dal tipo specifico di oggetti gestiti.
FrameworkAdapter: invoca i metodi concreti nel dominio specifico, serve per attuare operazioni
nell'interfaccia ristretta

Delegate Objects: si divide in
Delegate: specifica uninterfaccia ristretta includendo il contesto di dipendenza
FrameworkClassObj: delega le operazioni, in base al contesto, al LibClassDelegate. Espone un metodo
setDelegate () che consente l'installazione del delegato
FrameworkAdapterObj: Implementa il Delegate utilizzando SpecificClass. Si installa in FrameworkClassObj
come delegato (ad esempio nel costruttore)

UML (Unifiel modelling language)
Language: una notazione, pi tardi ne daremo un metodo di utilizzo
Modelling: adatto per lastrazione, maggiormente per lobject oriented
Unifield: una suite di diagrammi per approcci differenti, i quali con certe regole (core diagrams)
Class diagram: un core diagram nella suite UML, nativamente inteso in modo da catturare un OO
implementation ma equamente rilevante in altri livelli di astrazione e per intenti differenti. Serve per
catturare lorganizzazione delle classi, provvede ad una vista statica, infatti apre a differenti istanzazioni e
caratteristiche potenziali. Una classe intesa come un costrutto del OO language.

La visibilit: + public, # protected, ~ package protected, - private.
Posso indicare anche I tipi di parametri e del valore di ritorno. Es: init (size:int):void -> ho un parametro in
ingresso int e ritorna un void. I metodi virtuali li indico con il corsivo, = 0, apponendo << virtual >>. Gli
stereotipi in accordo con alcuni profili aggiungono sematica specializzata. Un esempio << persistent >>.
Lo scopo finale la comunicazione tra gli sviluppatori, si documentano le relazioni strutturali tra due classi.
Loggetto di una classe mantiene un riferimento ad un oggetto dellaltra classe, e viceversa.

Indica una direzione privilegiata, il medico ha un riferimento ad assistito, infatti di interesse sapere quanti
assistiti ha un medico e non quanti medici ha un assistito.

Il medico avr un elenco di assistiti, in cui c riferimento agli assistiti.

La * indica che potrei inserire anche un numero.



Documenta la situazione in cui metodi di una classe (cliente) istanziano unoggetto di unaltra classe
(ordine).
Documenta la situazione dove metodi di una classe dipendono da metodi o attributi di unaltra. diverso
dallassociazione poich uses non corrisponde ad una variabile della classe ma piuttosto a qualche
parametro passato in qualche invocazione.
Quindi la differenza tra associazione e uso che la prima documenta una relazione strutturale tra due tipi e
non un riferimento temporaneo entro i limiti di unoperazione. Quindi il link tra un medico e un paziente
unassociazione, il link tra un medico e un paziente iscritto per una visita una relazione di uso. Quindi la
prima un datamember con valore nellintera computazione, la seconda un puntatore ricevuto come
parametro nellinvocazione di un metodo.
Aggregazione: quando morto uno non muore laltro, cio se uno studente smette, non finisce il suo
corso di laurea.
Composizione: uno esiste solo grazie ad un altro. Se lo studente smette, il libretto universitario
sparisce.
La relazione di generalizzazione documenta sostituibilit (per le interfacce) e eredit nello stesso modo.
Un pediatra pu sostituire un medico, il contrario no.

Un package lo posso indicare in due modi.

Posso rappresentare istanze di classi con un class diagram: nellesempio un aereo ha due istanze diverse
dove gli attributi di flight assumono valore.
Object diagram:
Documenta lorganizzazione delle istanze delle classi in qualche fase significativa o esemplificativa
dellesecuzione. Rappresenta oggetti con i loro attributi che hanno assunto valore e relazioni tra oggetti.
Non un core diagram e serve solitamente per capire le conseguenze di un class diagram. ancora uno
static diagram. Notiamo che i tipi, cio le classi, si vedono quando scriviamo codice ma il run time fatto
di istanze. Abbiamo detto che gli stereotipi specializzano la semantica di qualche classe, per esempio <<
persistent >> indica che prendi da un database gli elementi e quando finisce riaggiorna il database. Gli
stereotipi si riuniscono in dei profili, spesso questi sono standardizzati in gruppi, ossia ci sono vari profili
standard: sysml, marte che specializzano luml attraverso stereotipi che prendono concetti dello specifico
dominio. Fare model driven development pu essere interessante perch scritto luml e generato il codice
verifico se luml corretto e allora mi dice che il codice corretto. In principio un modello implementativo
potrebbe essere 1:1 con la scrittura del codice ma la giusta strada tendente a una rappresentazione close
enough, ossia scrivere solo per capire il senso. Ho 3 livelli di astrazione:
1) prospettiva implementativa: rappresenta il modo in cui realizzato un sistema sw. Un oggetto nella
rappresentazione corrisponde ad un oggetto nel linguaggio OO.
2) prospettiva specificativa: rappresenta le astrazioni che saranno realizzate in un sistema sw. Un oggetto
della specifica realizzato attraverso pi oggetti nellimplementazione.
3) prospettiva concettuale: descrive lentit di un dominio applicativo che non per forza sono
rappresentate in una realizzazione sw.
Ho due intenti di rappresentazione: 1) specializzazione: di qualcosa che dovrebbe essere implementato, 2)
descrizione: di qualcosa che gi esiste.
Il class diagram nella prospettiva di specificazione astrae dai costrutti idioms di un linguaggio specifico.
essenziale per un progetto di alto livello. Utile per la descrizione di una architettura sw a differenti livelli di
granularit. Documenta lorganizzazione di un componente esistente. Pianifica lintegrazione e la
manutenzione.
Lassociation classes fornisce attributi e metodi per le associazioni (utilizzata nella prospettiva di
specializzazione e concettuale per guidare limplementazione).

Una generalizzazione si pu riferire a multiple direzioni ortogonali con un discriminatore per ogni direzione.

Ci sono altri costrutti
Vincoli: dentro alle parentesi graffe {}. Commenti: in dei riquadri contesto libero. Annotazioni: supportati
dai tool di modifica.
Il class diagram nella prospettiva concettuale: indipendente dalle possibili implementazioni dentro un
sistema informatico. Primariamente inteso per lanalisi e per la definizione dei requisiti. Abbiamo visto
che la vista statica data da:
1) class diagram: tipi e relazioni tra gli oggetti nei tipi 2) object diagram: un particolare istanza di tipi.
Invece nella vista dinamica (da vedere): 1) collaboration diagram e sequence diagram documentano la
sequenza dei messaggi scambiati tra un insieme di oggetti in uno scenario di esecuzione. 2) activity
diagram: aggiunge concetti di parallelismo e concorrenza.
Il sequence diagram tipicamente utilizzato per documentare la dinamica su un class diagram:

Quindi ci d il tempo di vita e di attivazione degli oggetti attivati in uno scenario di esecuzione. I messaggi
che si scambiano sono creazione, invocazione di metodi e self reference. La direzione verticale il tempo,
quella orizzontale gli oggetti. utile per descrivere la dinamica associata a schemi statici. Pericoloso nella
progettazione e nellanalisi. Il collaboration diagram rappresenta lordine degli eventi numerandoli
esplicitamente ma come il sequence diagram solo che privilegia la rappresentazione dellorganizzazione
degli oggetti.

Use case diagram e template
Requisiti funzionali: catturano il comportamento atteso dal system in termini di servizi, compiti e funzioni.
Ben inquadrati nel modello della specifica dei requisiti sw: srs 232.
Use case: la pratica dominante nella rappresentazione dei requisiti funzionali danno struttura e metodo
allidea di catturare requisiti funzionali a partire da esempi e scenari di interazione e uso. Quindi sono un
insieme di interazioni tra il sistema e 1 + attori esterni finalizzati ad un obiettivo. Gli attori sono unentit
esterna al sistema che interagisce con esso (pu essere una classe di utenti, un ruolo, un altro sottosistema,
una parte di sistema non sviluppata). Si dividono in attori primari che richiedono il supporto del sistema e in
attori secondari di cui ne richiede assistenza il sistema. Quindi in caso duso avviato da un attore con un
obiettivo e si conclude con successo con il raggiungimento di questo, cio si cattura chi fa cosa con quale
obiettivo attraverso quali passi. Si deve descrivere le varie sequenze con cui si raggiunge lobiettivo anche
quelle che conducono ad un fallimento per via di anomalie o errori. Uno scenario una specifica sequenza
del caso duso. Le interazioni includono stimoli e risposte, luse case non tratta di come il sistema
realizzato quindi si realizza una lista completa di casi duso che specifica tutti i differenti modi di usare il
sistema (quindi definisce il comportamento richiesto delimitando lo scope del sistema).
Use case diagram: visione dinsieme, relazioni tra attori e casi duso, strutturazione dei casi duso.

Caso duso un insieme di interazioni tra il sistema e uno o pi attori esterni finalizzati ad un obiettivo, con
varie funzioni. Poi c lattore (omino stilizzato) e la relazione di uso.

Lattore interagisce con il caso duso fornendo stimoli -> e ricevendo risposte <-. Un use case diagram non
documenta il flusso di informazioni n descrivere le relazioni di precedenza tra casi duso, secondo il
principio di break down funzionale lo svolgimento di un caso include quello di uno o pi sottocasi. Quindi
per fare questo si utilizzano le relazioni di inclusione finalizzate a partizionare la complessit infatti aiuta il
programmatore che per arrivare a dimostrare il caso deve aver implementato i sottocasi e il costo del caso
aggrega quello dei sottocasi. Quindi ho:
<< include >>: sottocaso, parte di un caso pi complesso
<< extende >>:punto di estensione
<< invokes >>: un caso ne invoca un altro: uguale a include + extende
<< precedes >>: un caso deve terminare prima dellavvio dellaltro

La generalizzazione (detta specializzazione) applicabile sia agli attori che ai casi duso. Un system
baundaries delimita i contorni e le interfacce di un sottosistema. Ho 4 diversi livelli di astrazione:
1) high summary: non una specifica sufficiente, definisce un ambito da analizzare
2) summary: fornisce visione dinsieme sui casi di livello user goal
3) user goal: specifica uninterazione ed il livello che conviene dettagliare con template testuali e mock
up
4) function: specifica un dettaglio dellinterazione che ha qualche particolarit, di solito non documentato
in modo individuale
Use case template: i singoli casi duso oltre ai diagrammi vengono documentati in forma testuale non
ambigua e semplice. Il linguaggio del dominio applicativo, meglio se riferito ad un modello concettuale
condiviso. In questa fase si deve abilitare un coinvolgimento di utenti ed esperti del dominio per seguire e
validare i casi duso e per definire i requisiti. Vediamo come si struttura.
Ucd:
Nome: deve suggerire lobiettivo del caso duso.
Numero di riferimento: per essere referenziato in altri casi, strutturato in forma gerarchica
History: chi ha creato/modificato il caso, quando e perch
Source: identifica da dove stato estratto il requisito, esempio derivato dal capitolo tecnico..
Livello: livello di astrazione utilizzato, tipicamente user goal
Description: lobiettivo descritto in un unico periodo nella prospettiva del contesto applicativo
Scope: organizzazione sistema componenti
Attori: attori coinvolti qualificati come primari e secondari. Esempio cliente (primary) sottosistema gestione
prenotazioni (secondary)
Precondition: le precondition necessarie a completare con successo il caso o comunque necessarie per non
dover fare riferimento a eventuali estensioni. Esempio il cliente ha gi un account.
Postcondition: le condizioni che si hanno al completamento del caso duso con successo o fallimento
dellobiettivo. Esempio viene messa una prenotazione caricata la carta di credito.
Normal flow: trigger: azione che avvia il caso. Passi: sequenza di interazioni tra attore e sistema necessaria
a raggiungere lobiettivo del caso i passi sono numerati descritti in un linguaggio naturale con eventuale uso
di alternative, ripetizioni e concorrenza.
Variazioni: specifica dove utile varianti con cui possono essere eseguiti singoli passi
Alternative flow: azioni che determinano diramazione rispetto alla sequenza comune dei passi che ne
seguono. Esempio 15.a il cliente abbandona la transazione.
Riferimenti: casi superordinati e/o subordinati
Requisiti non funzionali: requisiti architetturali o di qualit che per non sempre sono partizionabili sui
singoli casi duso. Esempio: performance 200 transazioni al minuto con tempi di attesa minori o uguali di 5
secondi.
Issues: elenco di aspetti che devono ancora essere chiariti con note su possibili strategie di
implementazione o sullimpatto verso altri casi, assunzioni fatte nello specificare il caso. Esempio il cliente
pu applicare il procedimento ai treni regionali?
Priorit: criticit rispetto al piano di sviluppo
Data di consegna: data o incremento in cui previsto o avvenuto il rilascio
Gli uses case non servono per progettare, descrivere procedure e partizionare il processo allinterno del
sistema ma servono a discutere e definire i requisiti funzionali, definire le interfacce di un sistema, a
partizionare le funzionalit. Possono essere utili per pianificare e monitorare lo sviluppo pianificando test.
I mock ups sono prototipi delle interfacce grafiche esposte allutente con struttura di navigazione delle
pagine e layout delle singole pagine. Si d particolare enfasi sullinformazione e le funzionalit nella
interazione tra utente e sistema ci astraiamo comunque dai dettagli di design grafico. Favoriscono il
coinvolgimento di utenti ed esperti di dominio, infatti vi troviamo una rappresentazione concreta, a basso
costo di evoluzione, e uno stimolo alla discussione. Si pu ritrovare in diverse fasi del progetto con
valutazioni di idee progettuali alternative allanalisi con la validazione dei requisiti fino ai test di
accettazione per il supporto della verifica di completezza.
Activity diagram
Una procedura una sequenza di attivit coordinate svolte in tempi diversi per effetto dellintrinseca
durata del processo da uno o pi attori per separare le competenze o le responsabilit. La procedura ha
uno stato, non si esaurisce in una transazione e si svolge in un arco di tempo, ciascuna attivit si svolge nel
contesto creato dalla precedente e opera sui dati e documenti condivisi. C frammentazione di
responsabilit, infatti le attivit sono svolte da pi soggetti e quindi manca una visione globale e un
approccio centralizzato sul flusso degli eventi. Ciascuna procedura eseguita su pi casi specifici. La
procedura interseca punti di cooperazione quali sistemi informativi infrastrutturali o applicativi o sistemi
esterni. C cooperazione con sistemi verticali che gestiscano in maniera autonoma informazioni rilevanti
rispetto ai singoli passi della procedura.

Ci sono 3 livelli di capacit nella gestione:
1) processo esplicitato: esiste una rappresentazione documentata e condivisa della procedura. Sostiene
lorganizzazione amministrativa, la formazione e lallocazione delle risorse umane.
2) processo attuato: esiste un sistema informativo che lo coordina. Lattuazione delle procedure, fornisce
efficienza e garantisce un livello di qualit.
3) processo ottimizzato: rispetto ai requisiti di qualit (efficacia) e sulluso delle risorse (efficienza).
Del processo esplicitato la rappresentazione pu essere espressa attraverso schemi visuali standard: uml,
uses case diagram, activy diagram, class diagram, ci manca da vedere lactivity diagram
Lactivity diagram adatto a descrivere procedure ed in qualche modo correlato al data flow diagram
dellanalisi strutturata. Adatto allanalisi di un use case favorendo lidentificazione delle operazioni non
degli oggetti a cui allocarle.
Un po di simboli:
:punto di partenza
: activity final node, punto di arrivo, termine dellesecuzione
: nodo di decisione, si utilizza per una condizione e quindi deve esprime la mutua esclusione
: fork node o join node attiva i flussi paralleli la sincronizzazione di pi flussi paralleli che procedono in un
unico flusso
: flow final node termina lesecuzione di un flusso lascia inalterato lo stato eventuale flussi paralleli
: manda il segnale x
: accetta il segnale x
Una subattivit
Connettori
Per arrivare allactivity diagram utilizzo il class diagram + attori + use cases. I passi dellanalisi sono 1)
verifica preliminare (il testo scritto) 2) identificazione classe attori e caso duso 3) organizzazione di
unactivity diagram
Schede crc (class responsability collaboration) si identifica un insieme di classi. Per ciascuna si elencano
le responsabilit salienti e per ciascuna si elencano le collaborazioni necessarie ad assolvere le
responsabilit. Sono utilizzate nellallocazione e identificazione delle responsabilit.
Design pattern
I) structured programming: tutti i costrutti che posso trovare in un linguaggio come il c
II) structured designed: lorganizzazione di funzioni, allocazione di responsabilit ai moduli, gerarchia
chiamato chiamante attraverso i moduli. In modo pi generale i dati sono decorazioni nelle funzioni
lo structured design astratto dalla procedura per enfatizzare le relazioni gerarchiche tra le funzioni.
Lo structured design utilizza un artefatto di modellazione: la carta strutturata, basata nelle metriche
di accoppiamento e coesione.
Carta strutturata un albero fatto di moduli e couples, dove i moduli sono funzioni e i couples sono
parametri legati alla chiamata a funzione, si dividono in data couple (tutto ci che riguarda i dati
indicati con (immagine)) e i control couple (tutto ci che pu far cambiare il flusso di controllo)
indicati con (immagine). I couple sono associati alle frecce che indicano se in input o output (ricordo
che in c ci si passa lindirizzo del valore per produrre un side effect). Poi ci possono essere variabili
condivise, che possono essere variabili globali, database, network.

Poi posso vedere annotazioni procedurali,
ripetizioni (while, for, ) segnati con
guardie (if, switch, ) segnati con
Metrica di accoppiamento: quanto pi te devi conoscere del modulo x per modificare in modo sicuro
il modulo y, una metrica di anti qualit infatti ostacola il mantenimento e levoluzione separata dei
moduli. Spinge verso lintegramento dei moduli, partizionamento topologico anche conosciuto come
refactoring. Laccoppiamento pu derivare da vari fattori:
1) chiamata a funzione: dipende dalla complessit dellinterfaccia e si passa control couple,
soprattutto dal chiamante al chiamato.
2) aree comuni: tipo un database
3) riferimenti topologici: non esplicitamente supportati in c
4) accoppiamento: pi alto prima il tempo in cui si fa. Esempio: compilazione, link, run time
percorrendo questi 3 allinverso ho che laccoppiamento cresce, ossia da run time a compilazione.
Laccoppiamento transitivo e le interfacce potrebbero servire per disaccoppiare.
Metrica di coesione: quanto due responsabilit allocate allo stesso modulo sono coesive lun laltra
(includendo le guardie sotto il modulo). una metrica di qualit: 1) responsabilit coesive
evolveranno insieme e saranno modificate dalle persone con domini omogenei 2) evita
mantenimento parziale 3) riduce il numero di ragioni per modificare un modulo 4) promuove il riuso.
C un indice di livelli di coesione: 0) coincidenza: quando due righe di codice che appaiono
frequentemente chiuse una nellaltra 1) logico: operazioni simili 3) temporali: operazioni eseguite a
istanti chiusi di tempo 5) procedurali: step legati insieme dalla struttura della procedura ed alcuni
criteri virtuali di coesione 7) comunicazionali: due moduli operano nello stesso data element 9)
sequenziali: due moduli dove il primo produce dati per il secondo 10) funzionali: due funzioni che
sono entrambe essenziali per altre funzioni (le chiavi del motorino e il casco) quindi si controlla la
coesione di funzioni allocate a moduli nello stesso sottoalbero e laccoppiamento attraverso moduli
differenti.
III) structured analysis: ci dice come si arriva a scrivere la carta strutturata. Voglio arrivare ad una
rappresentazione del flusso dellinformazione e delle sue trasformazioni come strumento di
modellazione useremo il data flow diagram e il metodo sar lanalisi delle trasformazioni e delle
transazioni.
Data flow diagram: documenta flussi e trasformazioni:
data flow: un flusso di informazione scambiata
process: trasformazione di informazione
data store: uninformazione persistente (qualcosa che ci rimane in vita dopo aver tolto la corrente)
terminator: un componente esterno del sistema
Il context diagram: documenta linterfaccia del sistema, un unico processo the system, indicato con il
numero 0.
Il levelling scompatto i vari dataflow diagram in unit pi specifiche di ogni singolo processo (espansione):
data flow diagram 0: espande il processo 0, data flow diagram i: espande il processo i come rete di processi
i. Poi ad un certo punto non espando pi un data flow diagram nel levelling e costituisco il process
specification (o anche detto pspec) che documenta la funzione di un processo non espanso in un data flow
diagram figlio. Associata ad un diagram ho sempre una documentazione. In questo caso avr il data
dictionary (possono essere struct del c). Il dfd un grafo e non un albero e si costruisce incrementalmente.
Non definisce un prima o un dopo n ripetizioni. In pi non ci rappresenta informazioni sul controllo. I
segnali e le condizioni di attivazione sono trasparenti. Le euristiche per la costruzione: iniziano con il
naming il quale ci dice che ci a cui non si riesce a dare un nome spesso non rispetta la semantica prevista.
Il processo un predicato con complemento, il flusso un sostantivo spesso il complemento oggetto del
processo ed ogni termine deve esprimere un concetto specifico ovvero un concetto atomico, quindi non
utilizzare un termine neutrale. Esempio file, archivio, dato, .
Il ripartizionamento topologico (refactoring): ci dice di unire i processi in un unico dfd e poi ripartizionarli
per coesione e accoppiamento o per livello semantico omogeneo tenendo conto della regola 7+/-2.
Posso dividere i moduli in afferenti quando trasforma linformazione dal livello fisico a quello logico e
modulo efferente viceversa. Si parla di rami afferenti (o efferenti) se si ha sequenza di moduli
afferenti/efferenti. Poi la trasformazione centrale il punto di trasformazione al massimo livello logico
alimentata in ingresso da rami afferenti in uscita da rami efferenti.
Un executive module (main) coordina: un modulo per la trasformazione centrale, un modulo get per ogni
ramo afferente e un modulo put per ogni ramo efferente. Vediamo come possibile espandere una
trasformazione centrale se ha uno pspec questo definisce la funzione da implementare nel modulo, se ha
un dfd figlio si ripete con la trasformazione centrale come executive del dfd figlio. Il modulo finale del ramo
afferente opera come trasformazione centrale e il modulo get alimenta con i dati ricevuti da un insieme di
modulo get. Il primo modulo del ramo efferente opera come trasformazione centrale e il modulo put
produce i flussi per un insieme di moduli put.
Si va incontro alliperstrutturazione che pu essere un limite nel mantenere visione. Si potrebbe pensare di
avere perdita di efficienza ma non un gran problema dato che pi facile far andare veloce un sistema
che funziona piuttosto che far funzionare un sistema veloce. limitato rispetto allo sviluppo ad oggetti
infatti basato sul concetto di coesione funzionale, rigido rispetto allevoluzione dei requisiti e scarsamente
orientato al riuso. Dato che fondamentale per lanalisi delle procedure e flussi incorporato come parte
dello sviluppo orientato ad oggetti.
Structured vs OODevelopment
Partiamo dalle differenze che ci sono tra OO program e structured program, non solamente una
questione di sintassi e di semantica. Infatti molto pi interessata alla struttura del codice con
conseguenze positive e negative. Vediamo i tre maggiori problemi: 1) stato, visibilit e accesso
concorrenziale 2) polimorfismo 3) complessit del flusso di controllo
Infatti per la structured program (sp) la carta strutturata fornisce una chiave di visione di come gira il
controllo, infatti era facile poich la gerarchia realizzava un insieme di funzioni smistate da uno o pi centri
di transazione. Invece nel OOP la topologia su cui avviene la computazione una rete di oggetti, la rete pu
svolgere pi corrispondenti a pi scenari duso. Ciascuno corrispondente a un diverso sequence diagram.
Quindi non c un modello predefinito che ci dice come gira il controllo. Ciascun oggetto trasferisce il
controllo alloggetto che detiene la responsabilit delegata e non ad un subordinato e quindi tra i due
spesso esiste una relazione di uno dinamica e non una relazione strutturale. dimostrato che OOP
favorisce levolvibilit, il riuso, la produttivit, infatti capace di assorbire una variet di responsabilit
coesive sui dati che tratta e in pi posso sempre attraverso la rete di oggetti rispondere ad un nuovo caso
duso, grazie anche alla possibilit di meccanismi di interazione complessi (come forwarding o inversione di
responsabilit). Quindi molto pi flessibile del SP, dove lintera gerarchia finalizzata a svolgere una
funzione con responsabilit coesive in senso funzionale. Tutto questo complica ulteriormente il testing di
OOP. In SP come abbiamo visto la gerarchia statica, invece in un OOP la topologia degli oggetti
largamente dipendente da scelte prese al tempo di esecuzione. Infatti gli oggetti sono instanziati in modo
dinamico ed in tipi diversi, in pi il prevalere delluso della delega rispetto alleredit esacerba il problema.
Andando avanti noto che in SP le variabili locali terminano il tempo di vita con la funzione e si fa un limitato
utilizzo della direttiva static e delle variabili globali. Invece in OOP un oggetto incapsula attributi che
mantengono il valore anche quando il controllo non risiede in uno dei metodi delloggetto. Questo prende il
nome di stato delloggetto. In pi gli attributi hanno visibilit globale entro la classe. Poi si registra
concorrenza dato che lo stesso oggetto pu essere visto da oggetti diversi e anche di tipo diverso. Gli
oggetti in sostanza danno visibilit globale e sufficiente a conoscerne lindirizzo, in sostanza si realizza un
uso pervasivo di quello che in c sarebbe un puntatore a funzione. (cosa che in c era limitato). In OOP la
stessa operazione pu essere implementata polimorficamente, posso infatti avere diverse forme
nellistanza concreta della classe. Poi si ridotto lutilizzo del costrutto if e poi ho diverse configurazioni
delle deleghe (vedi decorator).
A element of object oriented analysis:
Lanalisi di OO come caratterizzare alcuni domini concettuali in termini di classi, oggetti e relazioni. Spesso
un primo step nel processo per costruire unapplicazione sw. Un modello ha uno scopo pragmatico. Il
diagramma delle classi uml d una notazione effettiva e pratica ma il problema di fondo :
1) come identificare le classi e gli oggetti da rappresentare (e i loro attributi espressioni e relazioni)
2) come identificare e allocare responsabilit in accordo ai principi di coesione e disaccoppiamento.
Il processo di object modelling tecnique inizia con un problem statement che dovrebbe essere fornito dal
cliente. Da questo sviluppato un analysis model che una coincisa ma non ambigua rappresentazione di
concetti essenziali, riguardanti la comprensione del problem statement. Lanalysis model composta da tre
livelli ortogonali:
1) object model: descrive la struttura statica e lorganizzazione delle classi
2) dinamic model: le funzioni eseguite e quindi come lo stato pu evolvere
3) function model: gli algoritmi utilizzati per processare i dati
Vediamo come si divide i sw requirement specification (srs):
1) requisiti funzionali: cosa un sistema deve fare
2) requisiti architetturali: come la struttura della soluzione
3) requisiti di qualit: la qualit nelle funzioni e la struttura (ISO 91 26).
La separazione delle prospettive funzionali, strutturali, e qualitative cruciale, infatti un modo per
ottenere la decomposizione ortogonale della complessit. La prima attenzione dovrebbe essere posta sui
requisiti funzionali. Le prospettive funzionali e strutturali hanno rilevanza diversa in fasi diversi e per ruoli
diversi, la prima (funzionale) naturale per gli utenti e i clienti e prevale nella fase di analisi. La seconda
(strutturale) per gli sviluppatori e prevale nella fase di progetto. Quindi dato un testo si scoprono gli
oggetti e le funzioni, poi le classi e gli oggetti sono per convenienza rappresentate in class diagram
accompagnate da testo che provvede ad una non ambigua base per la discussione.
Gli elementi centrali: 1) classi evitano classificazioni gerarchiche facili da aggiungere ma rigidi a permettere
evoluzioni 2) associazioni: caratterizzate da nome e cardinalit 3) attributi: pochi senza lo scopo di
compattezza, spesso rappresentano concetti che serviranno successivamente delegati a classi esterne.
Le operazioni emergono molto pi tardi nel processo di analisi e progetto, infatti sono molto pi relative
alle specifiche che allanalisi concettuale. Associati strettamente con luse case e molto difficili da
identificare e allocare. Lidentificazione di classi e oggetti un compito per lanalista e non per il cliente che
oggetto e solitamente un nome come attributo, invece un metodo un predicato e loggetto il suo
complemento oggetto. Un oggetto pu avere attributi e operazioni che elaborano invece una classe un
tipo di uno o pi oggetti e quindi pu avere una singola istanza o molte. Ricordiamo che un valore correlato
ad un oggetto un attributo e non un oggetto. Quindi se per esempio voglio sapere se catalogo un
oggetto, mi posso domandare se ha uno stato o se questo pu essere creato o modificato nelle operazioni.
Se un valore caricato per essere un oggetto altrimenti probabilmente un attributo o giusto un valore.
Le operazioni sono allocate agli oggetti che esse modificano. Lidentificazione delle responsabilit e la loro
allocazione il vero cuore dellanalisi OO. Cio riguarda gli oggetti come entit capaci di assumere
responsabilit anche collaborando con altre entit.
Analysis pattern:
Accountability: ci dice come gestire la complessit di associazioni attraverso classi e oggetti. applicata
quando una persona o organizzazione responsabile di unaltra. una notazione astratta che pu
rappresentare molti problemi specifici. applicabile quando il dominio ha complessit significativa nella
struttura delle relazioni. Un modello diretto buono da disegnare ma non scalabile, per seguire
levoluzione delle questioni. Un supertipo di una persona, organizzazione o anche di una posizione che
condivide vari attributi.

La parola generalizzazione e le sue conseguenze sono il buono di riutilizzare attributi ma spesso gli
attributi dei sottotipi prevalgono nella complessit e serve pi per delegare future associazioni per
supertipi. Lo schema un party.

Le organizzazioni spesso hanno composizione gerarchica attraverso diversi tipi di componenti.

Il tipo di componente pu essere generalizzato in un supertipo. Il buono che lassociazione pu essere
condivisa con il supertipo, il male che i vincoli specifici potrebbero rompere la generalizzazione.

Questo pu essere superato dividendo in accountability e in accountability type, giustifica il tipo di
relazione attraverso i componenti e pu anche avvolgere le regole vincolanti.

Il knowledge level: ci dice qualcosa sulle regole generali di composizione, determina la struttura degli
oggetti per operation level ed evolve raramente.
Loperation level: ci sono istanze concrete di entit e le loro relazioni composte in accordo con gli oggetti
nel knowledge level e dunque evolve giorno per giorno. Nellesempio sopra evolve con un new party
quando una persona iscritta con new accountability quando una persona assegnata ad una entit.
Invece il knowledge level cambia solo con un new accountability type, quando un nuovo concetto di
responsabilit aggiunto nella struttura di organizzazione o con una nuova regola quando un nuovo vincolo
introdotto nella composizione.
Utilizzare un party type permette anche al party di evolvere, questo andr nel knowledge level: il valore di
party type specificher il tipo di un party. Fare sottotipi di party potrebbe anche essere necessario per
attributi specifici. La consistenza tra il type di party e il valore del proprio party type deve essere ottenuta
attraverso creazioni giudiziose. Le regole nelle composizioni applicabili sono vincoli tra valori dei party types
che possono essere composti dentro un accountability type.

Con un modello di questo tipo posso rappresentare quasi tutto, nella slide 15 ripropongo un modo pi
sofisticato del problema.
Observation and measurement: gestisce la complessit di attributi di un oggetto. Rappresentando una
misura come un attributo di un oggetto alla quale misura si riferisce. La misura potrebbe essere complessa
e condivisa da differenti tipi. Questo il modo comune di fare.

Se parlo di una misura di quantit posso mettere lattributo in un tipo cos mi permette il riuso del tipo e la
separazione del valore dallunit:

Poi posso delegare lunit ad una classe esterna:
Rapporto di conversione tra due unit: il numero potrebbe essere assorbito come un attributo di
conversion ratio.

Adesso posso vedere la misura e il tipo di fenomeno, cio porta fuori dalla misura il fenomeno che gli
associato. Introduce un knowledge level i cui oggetti identificano i tipi di un sottointeso operation level.

Quindi si pu salvare let associandolo ad una persona per una istanziazione che associata ad una istanza
di phenomenom type come pu essere il valore dellet e una istanza di quantity con il valore 48 che
associato ad unistanza di unit con il valore year.
Lobervation, una misura quantitativa spesso gioca lo stesso ruolo di un observation qualitativo per
esempio 48 et, cittadino europeo. Nel caso qualitativo la quantit rappresentata da una categoria che
prende i valori dentro a una enumerazione finita. Chiama observation per il supertipo comune.

Vediamo che category observation legata ad un qualitativo. Il measurement ad un quantitativo. In pi la
stessa istanza di category pu essere applicata a differenti phenomenom type (ma alte temperature non
come alte pressioni). Posso aggiungere phenomenon a knowledge level per specificare lintervallo di valori
di category observation. (Questo associato al phenomenon)

La febbre la posso indicare in modo qualitativo attraverso il category observation associato con una istanza
di phenomenon type con valore alto associato con un phenomenon type con valore temperatura oppure in
maniera quantitativa attraverso il measurement associato con unistanza di phenomenon type con valore
temperatura e associato ad unistanza di quantity con valore 38 che associato ad unistanza di unit con
valore C. Adesso posso aggiungere il protocollo, che caratterizza il modo in cui losservation stata presa
cio come stata effettuata la misurazione della temperatura. Posso aggiungere anche il time record che
associa uno o pi tempi di misura allobservation.

Un observation pu essere unipotesi, una proiezione nel futuro, unosservazione attiva: questo pu essere
rifiutato da un altro observation.

Il ciclo di vita dei sistemi sw:
Un prodotto un artefatto costruito nel corso dello sviluppo, ad esempio un programma eseguibile. Il
processo un insieme organizzato di attivit che conducono alla creazione del prodotto e quindi che ha a
che fare con come si fanno le cose pi che con le cose.
Waterfall lifecycle (royce 1970) identifica attivit specializzate separando competenze e ruoli. Si divide in:
1) studio di fattibilit: identificazione del problema e delle soluzioni. Si discute se il software si fa o si
compra
2) analisi e specifica dei requisiti: si produce il documento dei requisiti (srs), produco i class diagram per
descrivere il prodotto e gli use case per i concetti
3) progettazione: si definisce la struttura cio larchitettura di sviluppo, larchitettura sw e il progetto di
dettaglio
4) implementazione e test di unit: si decidono i concetti rispetto al linguaggio cio come mettere le classi e
i design pattern
5) integrazione e test di sistema: si integrano le varie parti che le costituiscono e si testa il sistema completo
6) deployment: si preparano i siti, faccio installazione e formazione sul nuovo software
7) manutenzione: pu essere evoluta sviluppando funzionalit o senn gestisco gli errori che potrebbero
avvenire
Nella separazione dei ruoli ciascuno sa fare una parte. Il modello a cascata consolida questa separazione
con artefatti intermedi, infatti al passaggio tra le fasi passata la documentazione. Nel 2000 si capito che
un progettista non pu fare un lavoro separato completamente da unanalista, la divisione dei ruoli diventa
cos un limite. Si arriva cos allevoluzione nel:
Modello a V: molto utilizzato adesso per i sistemi industriali (difesa, avionica, ferrovie). Si riorganizza il
modello waterfall partendo da una visione dinsieme scendendo fino ad una visione di unit per poi iniziare
a risalire riallargando la visione iniziando a fare test e integrazione da l in poi. Ho due dimensioni: 1) in
verticale: sistema/componente 2) in orizzontale: sviluppo/verifica. C feedback invece che tra livello
successivi tra livelli corrispondenti.

Sd1: analisi dei requisiti del sistema, cio ci sono dei requisiti contestuali che quando si va a fare il test
devono essere soddisfatti (come una data velocit di rotazione di un carro armato)
Sd2: sistem design: produce architetture di sistema unisce fondamentalmente le parti elettroniche,
meccaniche, informatiche, cio scompone in vari sottoparti da chi fa lanalisi di immagine a chi gestisce i
sensori e cos via
Sd3: sw/hw requirements analysis:ognuno fa lanalisi dei requisiti per il suo singolo ambito, informatica lo
fa per i singoli pezzettini di software.
Sd4 sw: preliminary software design: si fa design preliminare del software
Sd5 sw: detailed software design: faccio design in modo molto pi dettagliato delle parti sw a questo
punto mi sono ridotto a guardare lunit, dora in poi inizia ad implementare e fare testing, mandare
feedback di verifica dallaltra parte
Sd6 sw: sw implementation: faccio implementazione di ogni piccola parte e la testo
Sd7 sw: sw integration: faccio integrazione delle varie unit
Sd8: system integration
Sd9: transition to utilization. Lo standard mill std 498 era nato per la difesa militare statunitense poi ha
assorbito in ambito civile. Richiede la compilazione di un insieme di 22 documenti che si dividono in vari
settori, caratterizzati per fasi. Ognuno di essi mi elenca i requisiti
Srs: per ogni sottosistema produce lsrs
Irs: identifico cosa i vari sottosistemi espongono dato che vanno integrati con altri sottosistemi
Poi ci sono quelli relativi al design:
ssdd: la documentazione sulla progettazione del sottosistema.
Sdd: la documentazione solo sulla parte software dei miei sottosistema
Poi c quello per il test e la qualifica:
Stp: sw test plain
Std: sw test description
Str: sw test report
Poi ci sono i manuali di utenti, i manuali di supporto. Vediamo cosa sono i requisiti di qualit di un sw, cio
gli attributi in cui sono offerte le funzioni. Le standard ISO 91 26 divide le qualit dellsw in sei
caratteristiche:
1) functionaly: se contiene le funzioni richieste pi quelle intrinseche delloggetto (per esempio nel
telefono intrinseca loperazione chiamare)
2) efficiency: la velocit diviso le risorse
3) maintability: quanto facile da modificare
4) portability: quanto facile trasferire un sw in un altro ambiente
5) reability: come riutilizzabile il software
6) usabilit: quanto facile da utilizzare
Questo standard oltre a dividere le qualit in sei caratteristiche le divide in 27 sottoclassi, con intento di
completezza e indipendenza.
Il merito del waterfall lifecycle stato quello di essere stato il primo ad identificare attivit specializzate.
Questo modulo piace al corporate management in quanto semplifica la fase di contratto e visita di gestione
prestandosi bene a prevedere una successione di artefatti che documentano lavanzamento dello sviluppo.
Ma non piace al team degli sviluppatori, infatti non rappresenta i bisogni dellengineering view, infatti porta
al congelamento dei requisiti e delle scelte del progetto con un innaturale completamento delle fasi.
scarsamente flessibile rispetto allevoluzione dei requisiti e alla comprensione incrementale del progetto
infatti non si pu richiedere che lanalisi come qualunque altra fase possa terminare in un dato giorno.
Chiedere una fase prima potr creare problemi dopo, in pi si deve considerare per esempio che ci sono
aspetti di cui si deve fare lanalisi i momenti successivi dello sviluppo.
Un modello a spirale (bohem 1988)
Ogni iterazione percorre regioni di attivit comuni producendo un prodotto di maggiore rilievo
unevoluzione del waterfall che include la gestione del processo.


Punta inizialmente ad elminare quello che potrebbe fallire dopo attaccando prima le cose pi rischiose (se
anche elimino qualcosa che dopo non fallisce non elimino il problema) quindi punto a scegliere lalternativa
rispetto a quella meno rischiosa. La lunghezza della spirale proporzionale al tempo che sto impiegando,
invece larea della sua spirale sono i soldi spesi. Quindi allinizio della spirale conviene fare molti giri che
corrispondono a molto tempo ma a pochi costi con lidea che quando inizio ad aprire la spirale inizia ad
avere area maggiore cio iniziano le grandi spese ma spero di aver trovato la giusta strada. Questa modalit
si chiama risk driven cio dove prototipizzo cio dove rilasso qualche punto della qualit.
Il modello interattivo incrementale (mills 1980)
Svolgo parallelizzazione di attivit diverse relative a diversi incrementi, quindi rilascio per incrementi
successivi ciascuno in sequenza waterfall e ciascuno operativo (immagine)
I vantaggi sono che gli utenti sono coinvolti per feedback e testing quando verosimilmente un sistema base
funzionante. Poi posso consolidare il testing sui primi incrementi dando precedenza ai componenti pi
critici. Faccio in parallelo le varie operazioni, cio ho il team di analisi, design, codifica e test per tutte le
operazioni. Tutte le operazioni, questo crea difficolt contrattuali (una sorta di rivincita del team di sviluppo
sul corporate management).
Unifield process: procede in maniera iterativa con incrementi operativi, incentrato su unarchitettura
fissata al primo incremento e pilotato dai casi duso e dai fattori di rilascio. In un sistema complesso
necessario partizionare le responsabilit, cio separare i ruoli anche in relazione ai diversi livelli e localit di
competenza per ridurre la complessit (questo il problema del partizionamento). Questo partizionamento
non pu essere mai perfetto e quindi resta laccoppiamento, esistono sempre concetti nel modello di
dominio su cui intervengono pi casi duso allocati ad applicazioni separate. Occorre una architettura di
integrazione che ci permette di disaccoppiare lo sviluppo e la manutenzione (e anche i contratti).
Il CART unarchitettura di integrazione prevalentemente EDA, cio guidata dagli eventi.

Una executable architecture un sistema di coordinazione publish e subscrive, anche coinvolta come
mediatore degli eventi. Equivalente architettura del patter observer. I partecipanti sono:
1) publisher: pubblica un evento su un topic del mediatore
2) subscriver: sottoscrive un topic sul mediatore, accetta notifiche dal mediatore
3) broker: accetta eventi e li inoltra a tutti i sottoscrittori del topic
Il bus implementato con un message oriented middleware (mom).

Le applicazioni possono essere realizzate con tecnologie diverse ciascuna possibilmente supportata da un
messagging library. Ladapter mi serve per convertire i protocolli di interazione. Lapplicazioni
infrastrutturali possono estendere il bus.
Le architetture real time task set sono costituite da un set di task concorrenti, dove ciascuna task rilascia
dei jobs composti da chunks. I chunks sono sincronizzati su risorse (semafori). Il tipo di scheduling priorit
guidata da azioni preventive. I chunks implementano funzioni c che possono chiamare altre funzioni ma
non modificano luso delle risorse. Nellexecutable architecture vengono emulati i chunks da una funzione
busy sleep, larchitettura viene implementata ma manca completamente la funzionalit. Il ciclo di vita
articolato in 4 fasi ciascuna ha una pietra miliare:
1) avvio -> obiettivi: si fa lo studio degli obiettivi e delimitazione del progetto, cio si parla di fattibilit,
requisiti essenziali, rischi maggiori, consenso manageriale
2) elaborazione -> architettura: si definiscono l80% dei casi duso, si propone unarchitettura di base a si
pianifica la costruzione, valutazione delle risorse necessarie e si definisce il perfezionamento dellanalisi dei
rischi e la definizione di attributi di qualit
3) costruzione -> capacit operativa: si completano i requisiti e il modello di analisi e si guadagnano le
capacit operative iniziali: beta test
4) transizione -> rilascio: in questa fase si formano i siti utenti, i manuali e si fa preparazione e consulenza.
Poi c la parte di correzione dei difetti e di adattamento.

Ciascuna fase articolata in interazioni ciascuna delle quali organizzata come un sottoprogetto,
tipicamente ci sono pi iterazioni nelle fasi di costruzione. La durata per ciascuna iterazione di 1/2/3 mesi.
Il processo avanza con attivit che attraversano fasi e iterazioni: 1) requisiti, analisi, progettazione,
implementazione, test, rilascio 2) gestione, configurazione, infrastruttura di sviluppo. Dal grafico si nota un
diverso peso nelle diverse fasi per il flusso di lavoro, dove nelle prime iterazioni prevalgono i requisiti, nelle
ultime prevale il test. Quindi lUP un metaprocesso istanziato in ogni progetto in modo pi o meno
cerimonioso per la pianificazione specifica di artefatti intermedi, ruoli, strumenti di sviluppo, discipline di
archiviazione, attivit di gestione.

Extreme programming (back 1999)
un processo agile e adatto al cambiamento poich non c da perdersi in ogni passo dietro linfinita
documentazione. il passo estremo di supremazia del team di sviluppo sul corporate management. I
principi su cui si basa
1) rapid feedback: scrive un feedback rapido dellutente su come stato compreso il problema
2) assium semplicity: si deve mantenere le cose il pi semplice possibile dal scrivere un pezzo di codice
allutilizzare i design pattern
3) cambio incrementale: si migra tramite tante soluzioni intermedie con tante piccole variazioni
4) embrancing change: cio abbraccia il cambiamento infatti non siamo ingegneri civili che dato il progetto
rimane quello ma possiamo cambiarlo e adattarlo alle modifiche
5) quality work: il lavoro deve essere di qualit quindi deve essere veloce ma anche funzionare bene ed
essere modificabile
I valori su cui si basa la comunicazione tra gli sviluppatori e utente e il coraggio, deve cio provare tutto se
uno indeciso se una cosa funziona o no la prova lo stesso.

In teoria in una settimana dovrei fare tutti i colori cio produco gli use case diagram preliminari: ne prendo
uno e lo analizzo, progetto, implemento e testo. Le conseguenze di questo modo di fare sono:
1) evitare di prevedere: evitando il rischio di fare overdesign con funzionalit ad oggi inutili
2) evitare separazione dei ruoli: ciascun programmatore combina coding testing listening design. Quindi si
ha una riduzione della specializzazione dei compiti con comunicazione e feedback rapido dallo sviluppatore,
dallutente e dai test
3) si evita la produzione di semilavorati non strettamente necessari: sono molto usati gli use case diagram e
poco il resto. Si fa nuovo codice e test. La documentazione quindi sparisce data la vicinanza e condivisione
del lavoro.
4) il processo controllato attraverso pratiche pi che documenti
Le pratiche con cui si lavora in XP sono:
1) on site costumer: i committenti partecipano operando in sito nel corso di tutto lo sviluppo
2) planning game: lutente definisce i requisiti attraverso storie, cio racconta le funzionalit che vorrebbe
avere. Questi non sono casi duso ma questo che vorrebbe avere. A questo punto gli sviluppatori stimano
il costo delle storia. Gli tenti scelgono le storie realizzate nel prossimo incremento secondo un
compromesso tra costo realizzato e tempo di rilascio. Gli sviluppatori scompongono i task con le storie
scelte e scelgono i task.
3) rilasci piccoli: il sistema in produzione entro breve, un mese. I rilasci operativi sono ravvicinati ogni 2/3
settimane.
4) opersource: si fa bene a stare in spazi convidisi
5) integrazioni continue: il codice viene continuamente integrato in una visione comune
6) priorit collettiva: il codice di tutti e tutti lo possono integrare
7) test: si dividono i due categorie: quelli di unit fatti dal programmatore perch sa dove si trovano le
classi che si possono rompere, invece quelle funzionali sono fatti dallutente perch lui sa quello che vuole.
Il codice integrato si passa gli unit test, invece il rilascio chiuso quando passa i test funzionali
8) metafora: c una visione condivisa e coincisa degli obiettivi del progetto
9) simple design: modificare la struttura senza modificare il comportamento
10) coding standard: per aumentare la capacit autodocumentale del codice
11) programmare a coppie: le coppie sono formate di task in task da un fattore di continuit e
omogeneizzazione del team. Ovviamente il tutto pu avere problemi di applicabilit dato il: a) rischio della
stima dei costi b) richiede la cooperazione degli utenti c) il contratto difficile d) dimensione limitata del
team.
Le condizioni di migliore funzionamento sono in casi di progetti di breve durata (internet age) o processi
con requisiti instabili (per lapproccio esplorativo o come progetti di ricerca). La teoria classica di bohem
1976 ci dice che il costo di una modifica cresce esponenzialmente con lavanzamento. Poi siamo arrivati al
claim di XP del 2000 che sostiene che grazie alle tecnologie di testing, di refactoring di versioning e grazie
allobject orientation si pu dire il costo di una modifica cresce in modo logaritmico con lavanzamento.

You might also like