Progettazione del Software, Laurea in Ingegneria Gestionale
Università degli Studi di Roma “La Sapienza”
Facoltà di Ingegneria – Corso di Laurea in Ingegneria Gestionale
Corso di Progettazione del Software
Proff. Toni Mancini e Monica Scannapieco
Dipartimento di Informatica e Sistemistica
Università di Roma “La Sapienza”
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla
versione del February 26, 2008
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 1/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Associazioni a resp. multipla
In questo caso dobbiamo realizzare “entrambi” i versi dell’associazione, permettendo
l’interrogazione, l’inserimento e la rimozione di link a partire sia da oggetti di classe C che da
quelli di classe D.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 2/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Esempio
L’approccio più intuitivo consiste nel duplicare il codice visto per la gestione delle
associazioni a responsabilità singola, di fatto tendando di realizzare l’associazione come
due associazioni indipendenti (una per ogni verso):
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 3/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Esempio (cont.)
public class Persona {
private Set<TipoLink...> linkHaLavorato =
new HashSet<TipoLinkHaLavorato>();
public class Azienda {
private Set<TipoLink...> linkHaLavorato =
new HashSet<TipoLinkHaLavorato>();
pub v inserisciL..(Azienda az,Data da,Data a)
throws EccezionePrecondizioni {
linkHaLavorato.add(
new TipoLinkHaLavorato(this, az, da, a) );
}
pub v inserisciLink..(Persona p,Data da,Data a)
throws EccezionePrecondizioni {
linkHaLavorato.add(
new TipoLinkHaLavorato(p, this, da, a) );
}
public void eliminaLink..(TipoLink... l)
throws EccezionePrecondizioni {
if (l == null) throw
new EccezionePrecondizioni(
"Il link non puo’ essere null");
linkHaLavorato.remove(l);
}
public void eliminaLink..(TipoLink.. l)
throws EccezionePrecondizioni {
if (l == null) throw
new EccezionePrecondizioni(
"Il link non puo’ essere null");
linkHaLavorato.remove(l);
}
public Set<...> getLinkHaLavorato() {
public Set<...> getLinkHaLavorato() {
return (Set<.>)((Hash..)linkHaLav..).clone();
return (Set<.>)((Hash..)linkHaLav..).clone();
}
}
} //:˜
} //:˜
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 4/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Associazioni a resp. multipla (cont.)
I problemi di tale soluzione sono evidenti:
– Stiamo realizzando due associazioni indipendenti, non una!
– Non è più vero, quindi, che, per ogni coppia di oggetti p e az di classe Persona e
Azienda si ha che:
hp, azi ∈ p.haLavorato
se e solo se
hp, azi ∈ az.haLavorato
– In particolare, è il cliente che deve preoccuparsi di inserire un link da entrambi gli
oggetti, al fine di garantire che tale realizzazione rappresenti davvero un’unica
associazione a responsabilità doppia:
Persona mario = new Persona(...);
Azienda ibm = new Azienda(...);
Data da = new Data(3,2,1997);
Data a = new Data(5,6,2005);
mario.inserisciLinkHaLavorato( ibm, da, a );
ibm.inserisciLinkHaLavorato( mario, da, a );
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 5/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Associazioni a resp. multipla (cont.)
D’altra parte, se un cliente invocasse solo
mario.inserisciLinkHaLavorato( ibm, da, a );
il sistema sarebbe in grado di risalire al link hmario, ibmi solo a partire dall’oggetto
mario. Pertanto la situazione che ne deriverebbe è:
– mario ha lavorato per ibm;
– ibm non ha avuto mario come dipendente.
Tutto questo è evidentemente inaccettabile, perché porta ad un aumento spropositato
dell’accoppiamento (il cliente, per inserire un link, deve effettuare nell’ordine due
operazioni), oltre che seri rischi per la correttezza (il cliente deve conoscere i dettagli
implementativi del sistema per usarlo correttamente).
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 6/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Una prima soluzione
Una prima soluzione per gestire il problema è quella di offrire al cliente delle funzionalità per
inserire ed eliminare correttamente i link dell’associazione.
Tali funzioni saranno dichiarate static in una classe apposita, esattamente come se si
trattasse di operazioni di use-case:
public final class AssociazioneHaLavorato {
private AssociazioneHaLavorato() {}
public static void inserisciLink(Persona p, Azienda az, Data da, Data a)
throws EccezionePrecondizioni {
p.inserisciLinkHaLavorato(az, da, a);
az.inserisciLinkHaLavorato(p, da, a);
}
public static void eliminaLink(TipoLinkHaLavorato l) throws EccezionePrecondizioni {
l.getPersona().eliminaLinkHaLavorato(l);
l.getAzienda().eliminaLinkHaLavorato(l);
}
} //:˜
Ora il cliente, può seplicemente scrivere:
Persona mario = new Persona(...);
Azienda ibm = new Azienda(...);
AssociazioneHaLavorato.inserisciLink(mario, ibm, new Data(3,2,1997), new Data (5,6,2005));
e il sistema si occuperà dell’inserimento del link da entrambi gli oggetti.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 7/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Problemi di questa soluzione
Questa soluzione è corretta, perché, se il cliente usa le funzioni della class
AssociazioneHaLavorato ha la garanzia che i link vengono creati e distrutti
correttamente, ovvero da ambo le parti.
Tuttavia, questa soluzione evidenzia due importanti limitazioni:
1. niente impedisce al cliente di invocare direttamente i metodi (public peraltro)
inserisciLinkHaLavorato() e eliminaLinkHaLavorato() delle class
Persona e Azienda.
Pertanto, la correttezza è garantita solo in caso i clienti conoscano i dettagli
implementativi delle classi. Anche questa soluzione è quindi inadeguata allo scopo.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 8/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Problemi di questa soluzione (cont.)
2. Un secondo problema di questa soluzione è che, all’atto dell’invocazione di
AssociazioneHaLavorato.inserisciLink() i metodi
inserisciLinkHaLavorato() delle due class creano due oggetti distinti di class
TipoLinkHaLavorato (cf. l’implementazione di questi metodi). In sostanza, un link
UML viene rappresentato mediante due oggetti di class TipoLinkHaLavorato, che
quindi devono essere sempre mantenuti identici.
Se gli attributi di associazione sono mutabili, questa duplicazione diventa un serio
problema. Si consideri ad esempio il seguente frammento di codice cliente:
...
Iterator<TipoLinkHaLavorato> it = mario.getLinkHaLavorato();
while (it.hasNext()) {
TipoLinkHaLavorato l = it.next();
l.setAttributo(nuovoValore...);
}
Il cliente modifica il valore di un attributo del link l, ottenuto dall’oggetto di classe
Persona. L’oggetto di classe TipoLinkHaLavorato relativo allo stesso link
memorizzato nell’insieme del rispettivo oggetto di class Azienda resterebbe
immutato! Lo stesso link quindi, avrebbe valore diverso per l’attributo a seconda che
l’oggetto TipoLinkHaLavorato fosse stato ottenuto interrogando un oggetto di class
Persona o Azienda.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 9/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Problemi di questa soluzione (cont.)
L’obiettivo quindi è quello di:
1. obbligare il cliente ad usare le funzioni della class AssociazioneHaLavorato,
impedendogli di invocare direttamente i metodi inserisciLinkHaLavorato() e
eliminaLinkHaLavorato() delle classi responsabili dell’associazione.
2. Rappresentare un link UML mediante un solo oggetto di class TipoLink.
Risolveremo prima il punto 2., poi il punto 1.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 10/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Risolvere il punto 2.
– Facciamo in modo che sia AssociazioneHaLavorato.inserisciLink() a creare
un (unico) oggetto di classe TipoLinkHaLavorato e ha passarlo ai metodi
inserisciLinkHaLavorato() delle classi responsabili dell’associazione;
– Modifichiamo di conseguenza la segnatura dei metodi
inserisciLinkHaLavorato() delle classi responsabili dell’associazione, facendo
in modo che prendano in input non più l’oggetto linkato ed il valore degli attributi, ma
un oggetto di class TipoLinkHaLavorato, che sarà quindi condiviso tra gli oggetti
coinvolti nel link.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 11/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Risolvere il punto 2. (cont.)
Ad esempio:
public final class AssociazioneHaLavorato {
private AssociazioneHaLavorato() {}
public static void inserisciLink(Persona p, Azienda az, Data da, Data a)
throws EccezionePrecondizioni {
TipoLinkHaLavorato =
new TipoLinkHaLavorato(p, az, da, a);
p.inserisciLinkHaLavorato(l);
az.inserisciLinkHaLavorato(l);
}
...
} //:˜
public class Persona {
...
public void inserisciLinkHaLavorato(TipoLinkHaLavorato l)
throws EccezionePrecondizioni {
if (/* condizioni soddisfatte */) linkHaLavorato.add(l);
else throw new EccezionePrecondizioni(...);
}
...
} //:˜
Si ricordi che questa soluzione era stata scartata nel caso di responsabilità singola, perché
aumentava l’accoppiamento.
Tuttavia, vedremo che, risolvendo il punto 1., risolveremo anche questo problema.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 12/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Risolvere il punto 1.
Quello che ci resta da fare è obbligare il cliente ad usare le funzioni della class
AssociazioneHaLavorato per inserire ed eliminare link.
Il meccanismo che stiamo per illustrare in dettaglio fa in modo che i metodi
inserisciLinkHaLavorato() e eliminaLinkHaLavorato() possano essere invocati
solo dalle funzioni della class AssociazioneHaLavorato.
Si noti che non basta dichiarare tali metodi protected!
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 13/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Risolvere il punto 1. (cont.)
Il meccanismo è il seguente:
1. Modifichiamo la segnatura dei metodi inserisciLinkHaLavorato() e
eliminaLinkHaLavorato() delle classi responsabili dell’associazione,
aggiungendo un nuovo argomento di class AssociazioneHaLavorato;
2. Si noti che il costruttore della class AssociazioneHaLavorato è private, quindi,
gli unici moduli che possono creare tali oggetti sono le funzioni della class
AssociazioneHaLavorato stessa.
3. Le funzioni inserisciLink() e eliminaLink() della class
AssociazioneHaLavorato creano un tale oggetto e lo passano come argomento ai
metodi inserisciLinkHaLavorato() e eliminaLinkHaLavorato() delle class
Persona e Azienda.
4. Si osservi che la class AssociazioneHaLavorato non ha alcun campo dato, quindi
l’oggetto che viene creato e passato come argomento ai metodi
inserisciLinkHaLavorato() e eliminaLinkHaLavorato() delle class
Persona e Azienda non ha alcuna informazione rilevante.
Esso viene usato esclusivamente allo scopo di consentire l’accesso a questi metodi
solo a chi può crearlo, ovvero esclusivamente alle funzioni della class
AssociazioneHaLavorato (è una sorta di “pass”: solo chi è in grado di esibirlo può
invocare tali metodi).
5. Si osservi infine che la class AssociazioneHaLavorato è dichiarata final. Se così
non fosse, un cliente potrebbe sottoclassarla rendendo pubblico il costruttore, ed avere
accesso ai metodi inserisciLinkHaLavorato() e eliminaLinkHaLavorato()
delle class Persona e Azienda creando pass a piacimento.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 14/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Esempio
public final class AssociazioneHaLavorato {
private AssociazioneHaLavorato() {}
public static void inserisciLink(Persona p, Azienda az, Data da, Data a)
throws EccezionePrecondizioni {
AssociazioneHaLavorato pass =
new AssociazioneHaLavorato();
TipoLinkHaLavorato =
new TipoLinkHaLavorato(p, az, da, a);
p.inserisciLinkHaLavorato(pass, l);
az.inserisciLinkHaLavorato(pass, l);
}
public static void eliminaLink(TipoLinkHaLavorato l)
throws EccezionePrecondizioni {
AssociazioneHaLavorato pass =
new AssociazioneHaLavorato();
l.getPersona().eliminaLinkHaLavorato(pass, l);
l.getAzienda().eliminaLinkHaLavorato(pass, l);
}
} //:˜
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 15/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Esempio (cont.)
public class Persona {
private Set<TipoLinkHaLavorato> linkHaLavorato =
new HashSet<TipoLinkHaLavorato>();
...
public void inserisciLinkHaLavorato(
AssociazioneHaLavorato pass, TipoLinkHaLavorato l)
throws EccezionePrecondizioni {
if (pass == null)
throw new EccezionePrecondizioni(
"E’ necessario esibire un oggetto di class " +
"AssociazioneHaLavorato per invocare questo metodo!");
linkHaLavorato.add(l);
/* Nota: non devo piu’ effettuare alcun controllo
(ad es. che l != null, oppure che l.getPersona() == this)
perche’ sono sicuro che l’oggetto ‘l’ e’ stato creato
correttamente dal metodo
AssociazioneHaLavorato.inserisciLink()
(l’unico metodo che puo’ invocarmi!)
/
*
...
}
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 16/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Esempio (cont.)
public void eliminaLinkHaLavorato(
AssociazioneHaLavorato pass, TipoLinkHaLavorato l)
throws EccezionePrecondizioni {
if (pass == null)
throw new EccezionePrecondizioni(
"E’ necessario esibire un oggetto di class " +
"AssociazioneHaLavorato per invocare questo metodo!");
linkHaLavorato.remove(l);
// Anche qui non e’ necessario alcun controllo!
}
public Set<TipoLinkHaLavorato> getLinkHaLavorato() {
return (Set<TipoLinkHaLavorato>)
((HashSet<TipoLinkHaLavorato>)linkHaLavorato).clone();
}
} //:˜
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 17/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Esempio (cont.)
public class Azienda {
private Set<TipoLinkHaLavorato> linkHaLavorato =
new HashSet<TipoLinkHaLavorato>();
...
public void inserisciLinkHaLavorato(
AssociazioneHaLavorato pass, TipoLinkHaLavorato l)
throws EccezionePrecondizioni {
if (pass == null)
throw new EccezionePrecondizioni(
"E’ necessario esibire un oggetto di class " +
"AssociazioneHaLavorato per invocare questo metodo!");
linkHaLavorato.add(l);
}
public void eliminaLinkHaLavorato(
AssociazioneHaLavorato pass, TipoLinkHaLavorato l)
throws EccezionePrecondizioni {
if (pass == null)
throw new EccezionePrecondizioni(
"E’ necessario esibire un oggetto di class " +
"AssociazioneHaLavorato per invocare questo metodo!");
linkHaLavorato.remove(l);
}
public Set<TipoLinkHaLavorato> getLinkHaLavorato() {
return (Set<TipoLinkHaLavorato>)
((HashSet<TipoLinkHaLavorato>)linkHaLavorato).clone();
}
} //:˜
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 18/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Ass. a resp. mult. 0..* – 0..* (cont.)
Ricapitolando, per realizzare l’associazione assoc:
– Va prevista una nuova classe public AssociazioneAssoc con le seguenti
caratteristiche:
– È dichiarata final, per evitare che un cliente possa sottoclassarla;
– Ha un costruttore private, per consentire solo ai metodi interni di poter creare
oggetti della classe;
– Gli oggetti della classe vengono usati come “pass” per poter invocare i metodi
inserisciLinkAssoc() delle classi responsabili dell’associazione;
– È equipaggiata di metodi public static (simili ad operazioni di use-case) che
sono l’unico modo, per un cliente, di inserire link dell’associazione assoc:
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 19/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Ass. a resp. mult. 0..* – 0..* (cont.)
public final class AssociazioneAssoc {
private AssociazioneAssoc() {}
public static void inserisciLink(C c, D d, T attr) throws EccezionePrecondizioni {
// Creo un pass: solo i metodi di questa classe possono farlo!
AssociazioneAssoc pass = new AssociazioneAssoc();
// Creo il link
TipoLinkAssoc = new TipoLinkAssoc(c, d, attr);
// Inserisco il link nei due oggetti esibendo il pass
c.inserisciLinkAssoc(pass, l);
d.inserisciLinkAssoc(pass, l);
}
public static void eliminaLink(TipoLinkAssoc l)
throws EccezionePrecondizioni {
AssociazioneAssoc pass = new AssociazioneAssoc();
l.getC().eliminaLinkAssoc(pass, l);
l.getD().eliminaLinkAssoc(pass, l);
}
} //:˜
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 20/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Ass. a resp. mult. 0..* – 0..* (cont.)
– Le class responsabili dell’associazione, C e D, avranno i seguenti metodi
inserisciLinkAssoc(), eliminaLinkAssoc(), più il metodo getLinkAssoc()
che è definito allo stesso modo del caso a responsabilità singola:
public class C {
private Set<TipoLinkAssoc> linkAssoc =
new HashSet<TipoLinkAssoc>();
...
public void inserisciLinkAssoc(AssociazioneAssoc pass, TipoLinkAssoc l)
throws EccezionePrecondizioni {
if (pass == null)
throw new EccezionePrecondizioni(
"E’ necessario esibire un oggetto di class " +
"AssociazioneAssoc per invocare questo metodo!");
linkAssoc.add(l);
}
public void eliminaLinkAssoc(AssociazioneAssoc pass, TipoLinkAssoc l)
throws EccezionePrecondizioni {
if (pass == null)
throw new EccezionePrecondizioni(
"E’ necessario esibire un oggetto di class " +
"AssociazioneAssoc per invocare questo metodo!");
linkAssoc.remove(l);
}
public Set<TipoLinkAssoc> getLinkAssoc() {
return (Set<TipoLinkAssoc>)((HashSet<TipoLinkAssoc>)linkAssoc).clone();
}
} //:˜
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 21/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Ass. a resp. mult. 0..* – 0..* (cont.)
public class D {
private Set<TipoLinkAssoc> linkAssoc =
new HashSet<TipoLinkAssoc>();
...
public void inserisciLinkAssoc(AssociazioneAssoc pass, TipoLinkAssoc l)
throws EccezionePrecondizioni {
if (pass == null)
throw new EccezionePrecondizioni(
"E’ necessario esibire un oggetto di class " +
"AssociazioneAssoc per invocare questo metodo!");
linkAssoc.add(l);
}
public void eliminaLinkAssoc(AssociazioneAssoc pass, TipoLinkAssoc l)
throws EccezionePrecondizioni {
if (pass == null)
throw new EccezionePrecondizioni(
"E’ necessario esibire un oggetto di class " +
"AssociazioneAssoc per invocare questo metodo!");
linkAssoc.remove(l);
}
public Set<TipoLinkAssoc> getLinkAssoc() {
return (Set<TipoLinkAssoc>)((HashSet<TipoLinkAssoc>)linkAssoc).clone();
}
} //:˜
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 22/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Gli altri casi: assoc. 0..1, 1..1, n..m
La realizzazione delle associazioni a responsabilità multipla con vincoli diversi da 0..*
avviene secondo lo stesso schema.
Ovviamente, i metodi inserisciLinkAssoc() ed eliminaLinkAssoc() delle classi
responsabili si comporteranno di conseguenza:
– Se la class è coinvolta nell’associazione con un vincolo di molteplicità massima pari ad
1, avrà un campo dato di tipo TipoLinkAssoc e non Set. Inoltre, il suo metodo
inserisciLinkAssoc() potrà generare una EccezioneMolteplicita in caso di
link già esistente.
– Se la class è coinvolta con un vincolo 1..1, oppure n..m (m > 1), con n > 0 e/o m < *,
il metodo getLinkAssoc() può generare una EccezioneMolteplicita.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 23/31
Progettazione del Software, Laurea in Ingegneria Gestionale
La gestione delle eccezioni
Nel caso una delle due classi responsabili dell’associazione sia coinvolta con un vincolo di
molteplicità massima pari ad 1, l’invocazione del corrispondente metodo
inserisciLinkAssoc() da parte di AssociazioneAssoc.inserisciLink() può non
andare a buon fine, generando un’eccezione di tipo EccezioneMolteplicita.
public final class AssociazioneLavora {
private AssociazioneLavora() {}
public static void inserisciLink(Persona p, Azienda az, Data da)
throws EccezionePrecondizioni, EccezioneMolteplicita {
AssociazioneLavora pass = new AssociazioneLavora();
TipoLinkLavora = new TipoLinkLavora(p, az, da);
az.inserisciLinkLavora(pass, l);
p.inserisciLinkLavora(pass, l); // Puo’ generare EccezioneMolteplicita !!
}
...
} //:˜
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 24/31
Progettazione del Software, Laurea in Ingegneria Gestionale
La gestione delle eccezioni (cont.)
Consideriamo il seguente codice cliente:
Persona mario = new Persona(...);
Azienda ibm = new Azienda(...);
Azienda microsoft = new Azienda(...);
AssociazioneLavora.inserisci(mario, ibm, new Data(...));
AssociazioneLavora.inserisci(mario, microsoft, new Data(...)); // !!!
Al secondo inserimento (link hmario, microsofti), il metodo
mario.inserisciLinkLavora() genererà un’EccezioneMolteplicita.
Il problema è che abbiamo già inserito con successo il link nell’azienda microsoft!!! (cf.
l’istruzione az.inserisciLinkLavora(pass, l) in
AssociazioneLavora.inserisciLink().
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 25/31
Progettazione del Software, Laurea in Ingegneria Gestionale
La gestione delle eccezioni (cont.)
Abbiamo due modi di risolvere questo problema:
– Se solo una delle classi responsabili dell’associazione può generare
un’EccezioneMolteplicita, basta, nel metodo
AssociazioneAssoc.inserisciLink() aver cura di invocare prima il metodo
inserisciLinkAssoc() sull’oggetto di quella classe:
public final class AssociazioneLavora {
...
public static void inserisciLink(Persona p, Azienda az, Data da) throws... {
AssociazioneLavora pass = new AssociazioneLavora();
TipoLinkLavora = new TipoLinkLavora(p, az, da);
p.inserisciLinkLavora(pass, l); // Puo’ generare EccezioneMolteplicita !!
az.inserisciLinkLavora(pass, l);
}
...
} //:˜
In questo modo, se il metodo genera effettivamente un’eccezione,
AssociazioneAssoc.inserisciLink() termina a sua volta senza aver modificato
nulla.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 26/31
Progettazione del Software, Laurea in Ingegneria Gestionale
La gestione delle eccezioni (cont.)
– Nel caso in cui invece più di una classe responsabile ha vincolo di molteplicità
massima pari ad 1, non abbiamo modo di riordinare le invocazioni dei metodi
inserisciLinkAssoc(), e dobbiamo procedere catturando le possibili eccezioni e
prendendo opportuni provvedimenti:
public final class AssociazioneAssoc {
...
public static void inserisciLink(C c, D d, T a) throws EccezionePrecond..., EccezioneMoltepl... {
AssociazioneAssoc pass = new AssociazioneAssoc();
TipoLinkAssoc l = new TipoLinkAssoc(c, d, a);
c.inserisciLinkAssoc(pass, l); // Puo’ generare EccezioneMolteplicita
/* In questo caso il metodo inserisciLink() si interrompe
a sua volta, e il sistema rimane invariato */
try {
d.inserisciLinkLavora(pass, l);
} catch(EccezioneMolteplicita e) {
/*non sono riuscito ad inserire il link in ‘d’: devo eliminare il link inserito
correttamente in ‘c’ e rilanciare l’eccezione per informare il cliente: */
Iterator itC=c.getLinkAssoc();// Si noti che sebbene l’invocaziowhile (itC.hasNext()) {
// ne di c.inserisciLink...() sia
if (l == itC.next()) {
// andata a buon fine, e’ possibile
c.eliminaLinkAssoc(pass,l);// che nell’insieme ‘c.linkAssoc’
break;
// fosse gia’ presente un link equal
}
// ad ‘l’. In questo caso
}
// ‘linkAssoc.add(l)’ **non** ha avuto
throw e;
// alcun effetto, ed ora non devo eli}
// minare ‘l’! Percio’, prima di in}
// vocare ‘c.eliminaLink...()’ devo assicurarmi
...
// che ‘l’ sia stato **davvero** aggiunto in ‘c’.
}//:˜
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 27/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Una variante
I metodi inserisciLinkAssoc() ed eliminaLinkAssoc() delle classi responsabili
dell’associazione prendono due argomenti:
– Il pass, ovvero un oggetto di class AssociazioneAssoc, che non ha attributi;
– Il link da inserire/eliminare, ovvero un oggetto di class TipoLinkAssoc.
La variante consiste nel modificare la class AssociazioneAssoc inserendo un campo dato
di tipo TipoLinkAssoc. Il pass dunque, ‘contiene’ al suo interno (come attributo
immutabile) l’oggetto di classe TipoLinkAssoc da inserire/eliminare.
Ora i metodi inserisciLinkAssoc() ed eliminaLinkAssoc() delle classi responsabili
possono prendere un solo argomento, il pass, al cui interno è contenuto il link da
inserire/eliminare.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 28/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Una variante (cont.)
public class AssociazioneAssoc {
private final TipoLinkAssoc link; // <---- Il link!
private AssociazioneAssoc(TipoLinkAssoc l) { link = l; }
public TipoLinkAssoc getLink() { return link; }
public static void inserisciLink(C c, D d, T a) throws ... {
...
/* Creo il pass contenente il link */
AssociazioneAssoc pass =
new AssociazioneAssoc( new TipoLinkAssoc(c, d, a) );
/* Ora devo passare solo il pass: il link
e’ all’interno */
c.inserisciLinkAssoc(pass);
d.inserisciLinkAssoc(pass);
}
public static void eliminaLink(TipoLinkLavora l) throws ... {
AssociazioneAssoc pass =
new AssociazioneLavora( l );
l.getC().eliminaLinkAssoc(pass);
l.getD().eliminaLinkLavora(pass);
}
} //:˜
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 29/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Una variante (cont.)
public class C {
...
public void inserisciLinkAssoc(AssociazioneAssoc pass) throws... {
...
TipoLinkAssoc l = pass.getLink(); // <---- Il link!
...
}
public void eliminaLinkAssoc(AssociazioneAssoc pass) throws... {
...
TipoLinkAssoc l = pass.getLink(); // <---- Il link!
...
}
...
} //:˜
(idem per la class D)
Si osservi come:
– Il costruttore (private di AssociazioneAssoc ora prende come argomento un
oggetto di class TipoLinkAssoc;
– La class AssociazioneAssoc ha un metodo public TipoLinkAssoc
getLink() per consentire ai metodi delle classi responsabili dell’associazione di
accedere al link a partire dal pass.
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 30/31
Progettazione del Software, Laurea in Ingegneria Gestionale
Associazioni n-arie
Si trattano generalizzando quanto visto per le associazioni binarie.
In particolare, la classe TipoLinkAssoc avrà n (e non solo 2) campi dati per memorizzare
gli oggetti linkati;
Nota. In questi casi è molto conveniente prevedere una class TipoLinkAssoc anche per
le associazioni senza attributi!
T. Mancini & M. Scannapieco
S.R.4 – La fase di Realizzazione: realizzazione di associazioni a resp. multipla – February 26, 2008 – p. 31/31