Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
vuoi
o PayPal
tutte le volte che vuoi
USES
A uses B significa che A può accedere ai servizi esportati da B attraverso la sua interfaccia. È definito
"staticamente". A dipende da B per fornire i suoi servizi. Quindi A è un cliente di B.
IS_COMPONENT_OF
Usato per descrivere un modulo di livello superiore come costituito da un certo numero di moduli di livello
inferiore. A IS_COMPONENT_OF B significa che B è costituito da diversi moduli, di cui uno è A.
INHERITS
Se il sistema è sviluppato in uno stile orientato agli oggetti, la relazione di ereditarietà consente a un
componente di estenderne un altro. Un erede può accedere ai segreti (alcuni) del suo antenato. I componenti
sono più fortemente connessi con INHERITS che tramite USES.
Contratti
Il modulo (classe) è di per sé una risorsa: è usato da altri per generare istanze. Si introduce la relazione di
ereditarietà, per fattorizzare una parte comune in un componente. Le modifiche (variazioni) sono dei delta
definiti nei sotto-componenti. L'ereditarietà aggiunge ulteriori interdipendenze tra i moduli.
Il design per contratto raffina un principio di design noto, particolarmente adatto per la progettazione OO:
l'interfaccia del modulo (classe) definisce un contratto. Un contratto è un accordo tra un cliente e un
imprenditore. Definisce gli obblighi per ottenere i benefici.
Le precondizioni definiscono ciò che ogni metodo richiede (obbligo per il cliente), mentre le post-condizioni
definiscono ciò che fornisce ogni metodo (obbligo per il contraente). Le precondizioni e le post-condizioni
possono essere espresse usando la logica.
Dovrebbe essere preparata una routine per gestire eventuali input? NO! Ma se la precondizione è debole
(TRUE ovvero senza alcun vincolo), tutti i controlli sarebbero delegati alla routine. Se invece se precondizione
è forte (FALSE ovvero che non può essere invocata da nessuno) la routine non lavora mai. La scelta del
presupposto è una decisione di progettazione: non esiste una regola assoluta, però è preferibile scrivere
semplici routine che soddisfano un contratto ben definito piuttosto che una routine che cerca di tentare ogni
situazione immaginabile.
Possiamo specificare una proprietà che tutti i casi dovrebbero soddisfare: l’invariante. L'invariante è vera
dopo la creazione e prima e dopo ogni operazione. L'invariante definisce un ulteriore obbligo di prova:
l’implementazione della classe la deve soddisfare.
Quindi in una classe:
1
Costruttori: precondizione -> costruttore -> invariante
1
Metodi: precondizione & invariante -> metodo -> post-condizione & invariante
Per le precondizioni vale che il cliente è responsabile della loro verità, ma può essere impossibile valutare
l'applicabilità prima dell'applicazione dell'operazione.
Le eccezioni dovrebbero essere sollevate se una delle seguenti condizioni è violata:
Precondizione
Invariante
Post-condizione
Quando il controllo lascia una routine, la sua post-condizione e l'invariante sono vere o viene restituita
un'eccezione. Le eccezioni restituite dovrebbero essere elencate nell'interfaccia della routine.
Le sottoclassi possono aggiungere attributi e metodi e possono ridefinire i metodi, ma hanno dei vincoli
sintattici: covarianza del risultato e contro varianza dei parametri. Inoltre ci sono dei vincoli di semantica:
precondizioni della classe sono figlie delle precondizioni della sottoclasse, mentre le post-condizioni della
sottoclasse sono figlie delle post-condizioni della classe. Ovvero: data una classe A e una sua sottoclasse B, ci
sia un metodo in A che restituisce C e che ha come parametro E, allora se B ridefinisce questo metodo
facendogli restituire D e dandogli come parametro F, deve valere che D estenda C e che E estenda F.
Stili
La comprensione condivisa delle forme di disegno comuni è tipica dei campi di ingegneria maturi. Il
vocabolario condiviso di idiomi di progettazione è codificato in manuali di ingegneria. Il software sta andando
in questa direzione: ma c'è meno maturità.
Esistono componenti e connettori. I componenti possono essere: client, server, filtri, database, strati, …,
mentre i connettori possono essere: chiamate a procedure, eventi broadcast, protocolli database, tubi, ….
Architettura funzionale
Il sistema si decompone in operazioni astratte. Le operazioni si conoscono e si chiamano l’un l’altra. I
connettori sono le chiamate a procedure e i valori di ritorno. Ci sono connettori aggiuntivi tramite dati
condivisi. Esso è lo sviluppo di sistema "tradizionale": le funzioni sono subroutine di programmi monolitici e
i dati sono dati "comuni" tra le routine. Sviluppo di sistema orientato agli oggetti: le funzioni sono metodi di
una classe e i dati sono i dati della classe.
Sistema a strati
Il sistema è organizzato attraverso livelli di astrazione, come una gerarchia di macchine astratte (cipolla).
L’ereditarietà e la gerarchia sono date dalla relazione USE.
Tubi e filtri
I filtri ottengono e mettono i dati sui loro tubi di ingresso e uscita; ignorano l'esistenza (e l'identità) di altri
filtri. Sono possibili diversi regimi di controllo: batch sequenziali e batch concorrenti. I vantaggi sono: che il
sistema è compositivo (comportamento complessivo come composizione dei comportamenti individuali),
orientamento al riuso (tutti i filtri possono essere messi insieme in linea di principio) e la facilità di modifica
(si può aggiungere/sostituire i filtri). Gli svantaggi sono che non c’è persistenza e la tendenza a un
organizzazione a batch.
Sistemi basati su eventi
Gli eventi vengono trasmessi a tutti i componenti registrati. Nessuna denominazione esplicita del
componente bersaglio. I suoi vantaggi sono: che gli eventi vengono trasmessi a tutti i componenti registrati,
che non c’è nessuna denominazione esplicita del componente bersaglio, che sono sempre più utilizzati per
le moderne strategie di integrazione e che è facile aggiungere e cancellare registrazioni di componenti. Gli
svantaggi sono che ci possono essere potenziali problemi di scalabilità e che non esiste un ordine degli eventi.
Sistemi basati su repository
I componenti comunicano solo attraverso un repository. Di solito i componenti sono attivi, il repository è
passivo e un ulteriore componente (gestore transazioni) legge le transazioni di ingresso e chiama funzioni
appropriate.
Ma esistono anche casi (come il caso Blackboard) dove i componenti leggono e scrivono nel Blackboard. Le
modifiche dello stato del Blackboard attivano dei componenti: un Blackboard è un repository attivo.
UML
Ragionare sui sistemi complessi è difficile. Costruire sistemi complessi è difficile. Come valutare aspetti
notevoli dei sistemi o l’efficacia di soluzioni costruttive senza affrontare l’intera complessità di un sistema
reale?
I modelli rappresentano il linguaggio dei progettisti: rappresentano il sistema da costruire o costruito, sono
un veicolo di comunicazione e descrivono in modo “visuale” il sistema da costruire. I modelli sono uno
strumento per gestire la complessità. I modelli consentono di analizzare caratteristiche particolari del
sistema.
Un sistema reale è caratterizzato da un alto numero di elementi e spesso solo una minima parte di tale
elementi risulta “interessante”, dove “Interessante” dipende dal contesto. Un modello può e deve trascurare
i dettagli irrilevanti. L’astrazione è la descrizione di un sistema (o di parte di esso) che ne riporta solo le
caratteristiche rilevanti. Un sistema è modulare se è diviso in parti che hanno una sostanziale autonomia
individuale ed una ridotta interazione con le altre parti: i moduli sono scarsamente connessi e fortemente
coesi (divide et impera).
La scomponibilità modulare consiste nel scomporre un problema in sotto-problemi di minori dimensioni e
quindi più facilmente affrontabili. La componibilità modulare consiste invece nel riaggregare moduli esistenti
per risolvere problemi nuovi avendo così riusabilità. La comprensione modulare consiste nel capire un
modulo osservando solo quello e i "confinanti”. La continuità modulare si ha se un piccolo cambiamento nelle
specifiche comporta cambiamenti in un solo (o pochi) moduli implementando così l’estendibilità. La
protezione modulare si ha se errori in un modulo influenzano solo il modulo stesso (o al massimo si
propagano ai confinanti).
Un modulo deve comunicare con il minor numero possibile di moduli: in un sistema con n moduli il numero
di comunicazioni deve essere vicino a (n - 1) e lontano da n * (n - 1) / 2 (poche comunicazioni). Ogni modulo
deve scambiare il minor numero possibile di informazioni con gli altri moduli (interfacce piccole). Il fatto che
due moduli A e B comunichino deve risultare evidente sia dal codice di A che dal codice di B (interfacce
esplicite). Il modulo deve distinguere tra informazioni pubbliche ed informazioni private (information hiding).
Un sistema complesso ha molteplici “aspetti” che devono essere descritti per rappresentare adeguatamente
il sistema. Difficile comprimere in un unico modello informazioni di natura anche molto diversa. Soluzione:
non un modello, ma più modelli, ciascuno specializzato per fornire un certo tipo di informazioni.
L’attività di sviluppo del software produce svariati semilavorati, ognuno di essi è scritto in un qualche
“linguaggio”:
Linguaggi di programmazione e affini (C++, Java, HTML)
Linguaggi naturali (italiano, inglese)
Linguaggi di descrizione
Le “descrizioni” vengono prodotte in svariate fasi del processo. I linguaggi di descrizione sono linguaggi adatti
a scrivere “descrizioni”. Le loro caratteristiche sono:
Completezza: il linguaggio deve mettere a disposizione strumenti per descrivere tutti gli aspetti di
interesse
Accuratezza: si deve poter costruire una descrizione precisa
Consistenza: il linguaggio deve aiutare a evitare contraddizioni in diverse rappresentazioni nella
stessa descrizione
Comprensibilità: la descrizione deve essere facilmente comprensibile da parte di chi la deve
interpretare (per modificarla, per utilizzarla come riferimento)
Formalità: rigore con cui sono definite la sintassi e la semantica del linguaggio
Stile: quale aspetto del sistema è più facile descrivere utilizzando il linguaggio (comportamento o
proprietà)
I linguaggi di descrizione possono essere:
Informali: tipicamente linguaggi naturali (italiano, inglese), spesso usati perché sono facilmente
comprensibili dal committente
Semi-formali: hanno