Programmazione Ad Oggetti
Programmazione Ad Oggetti
Introduzione al corso
Programmazione Orientata Agli Oggetti: OOP è un paradigma di
programmazione, che insieme a molti altri si è consolidato nel tempo per organizzare
e strutturare la scrittura di software. Si basa sul fatto che i sistemi software siano
un insieme di oggetti software che interagiscono tra loro.
Introduzione a Java
"Scrivi una volta, esegui ovunque". Java garantisce la portabilità attraverso la Java
Virtual Machine (JVM). Tutto in Java è un oggetto o una classe, promuovendo la
riutilizzabilità del codice e un design sistematico
(Definizione) JVM: La JVM è un motore di esecuzione che permette ai programmi
Java di essere eseguiti su qualsiasi dispositivo o sistema operativo che disponga di una
JVM compatibile, incarnando il principio "Write Once, Run Anywhere".
I programmi Java vengono compilati in bytecode, che la JVM interpreta ed esegue
HELLO WORLD
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World... again!");
}
}
Java è case sensitive, distingue tra lettere maiuscole e minuscole. public è una
parole chiave, modificatore di accesso, controlla il livello di accesso che le altre
parti del programma hanno su questo codice. class è una parola chiave ed indica la
definizione di una classe: tutto il Java è una classe; le classi sono i componenti
principali di un programma Java. HelloWorld è il nome della classe (la
convenzione per i nomi delle classi è UpperCamelCase) . Il nome del file sorgente
contenente questo codice deve avere lo stesso nome della classe pubblica
(HelloWorld.java).
Entrypoint di un programma Java: Un programma compilato viene lanciato
tramite il comando java NomeClasse. A questo punto la JVM inizia l'esecuzione
del codice definito nel metodo main della classe indicata.
Esecuzione del metodo main: Il codice sorgente di un programma deve
avere almeno una classe, solitamente la classe Main, con il metodo main
definito. Tale metodo deve contenere tutte le operazioni da eseguire al lancio
del programma.
Tipi di dato
Java è un linguaggio fortemente tipizzato, ci sono 8 tipi primitivi:
4 tipi di interi: int, short, long e byte
2 tipi di decimali: float, double
Il tipo char per i caratteri
Il tipo boolean per valori di verità booleani (true oppure false)
Variabili
Dichiarazione di una variabile: La dichiarazione di una variabile è formata da
un tipo e da un nome. Il tipo deve essere già definito (tipo primitivo o classe),
mentre il nome deve iniziare con una lettera.
Inizializzazione di una variabile: L'inizializzazione consiste nella
dichiarazione di una variabile e il successivo assegnamento di un valore.
L'assegnamento avviene tramite l'operatore di assegnamento =. Si può
utilizzare il valore di una variabile soltanto dopo l'inizializzazione. Dichiarazione
+ Assegnamento = Inizializzazione
Costanti
Dichiarazione di una costante: Un tipo di variabile il cui valore è immutabile. Una
volta assegnato il valore ad una costante, questo non potrà più essere modificato. Una
costante è identificata dalla parola chiave final.
Enums:
Un tipo di dato speciale che consente a una variabile di essere un insieme di
costanti predefinite. In Java, enum simboleggia un gruppo di costanti.
Operatori
Operatori aritmetici: +, -, * , /
/ esegue la divisione intera se gli operandi sono interi, altrimenti divisione
decimale
% è il resto intero di una divisione (anche chiamato modulo)
Gli operatori aritmetici possono essere combinati con l’assegnamento: x += 1;
è equivalente a x = x + 1;
Operatori di incremento e decremento: ++, -- ( Gli operatori di incremento e
decremento hanno una forma prefix e postfix )
Operatori relazionali: == , !=, , <=, >=
Operatori booleani: &&, ||, !
Conversioni
Conversioni in operazioni binarie: In Java, durante l'esecuzione di operazioni
binarie (ad esempio, addizioni o sottrazioni) tra due operandi di tipi differenti, il tipo di
dato "minore" viene automaticamente convertito al tipo "maggiore" per
garantire la compatibilità e prevenire la perdita di precisione.
Cast esplicito: Quando una conversione automatica non è possibile o si desidera
forzare una conversione a un tipo "minore" (che potrebbe portare a perdita di
informazione), si utilizza il cast esplicito. Si specifica il tipo desiderato tra parentesi
prima dell'operando.
Blocchi
Un blocco è un insieme di istruzioni delimitato da parentesi graffe { }. I blocchi
definiscono lo scope delle variabili, ovvero dove queste sono visibili dal resto del
codice.
Istruzioni condizionali:
Permette al programma di prendere decisioni, eseguendo diversi blocchi di codice a
seconda che una condizione sia vera o falsa
Per selezioni multiple con diverse alternative si può usare il costrutto switch che ha
una condition, una serie di case e un default:
Ciclo While:
Un costrutto che permette di eseguire un blocco di istruzioni finché una condizione
è valida.
Ciclo For:
Il ciclo for itera per un numero di volte dettato da un contatore e da una o più̀
condizioni su di esso. La testa di un ciclo for può̀ contenere diverse espressioni; in
genere si utilizzano solo una inizializzazione, una condizione di test e un incremento o
decremento.
Array:
È una sequenza omogenea di elementi (primitivi o oggetti) identificato da un
unico identificatore. Un array può contenere elementi di un solo tipo. Per definire
un array si usa il l’operatore di indexing []. La dichiarazione di un array ha la forma
T[] a; dove T è il tipo degli elementi nell'array. Si legge: array di T.
Per allocare lo spazio per gli elementi di un array abbiamo bisogno di inizializzarlo.
Funzioni:
È un insieme di istruzioni che compie un'operazione definita. La "firma" di una
funzione comprende il suo nome, il tipo di ritorno e la lista dei parametri, e
serve a identificarla univocamente all'interno del suo ambito.
3.CONCETTI DI PROGRAMMAZIONE
Programmazione orientata agli oggetti
OOP è il modello predominante nella programmazione moderna, pone i dati
(oggetti) al centro dell'attenzione, promuovendo un approccio più strutturato e
intuitivo allo sviluppo software.
Classi ed oggetti
Una classe è una struttura che definisce le caratteristiche (attributi) e i
comportamenti (metodi) che saranno condivisi da un gruppo di oggetti.
Funziona come un blueprint da cui gli oggetti sono creati.(auto)
Un oggetto è un'istanza di una classe. Ogni oggetto ha uno stato e un
comportamento definiti dalla sua classe ma può mantenere i propri valori degli
attributi, distinguendosi così dalle altre istanze( audi,nissan,volvo etc.)
Quando si crea un oggetto dalla classe, si dice che la classe è stata istanziata (o è
stata creata un'istanza della classe). La libreria standard Java fornisce migliaia di
classi per scopi diversi. Possiamo creare tutte le classi necessarie a modellare le entità
del nostro software. L'esecuzione del software consisterà nell'interazione tra le
istanze delle classi definite in esso.
Identificare le classi
Approccio Orientato agli Oggetti: Potrebbe sembrare meno intuitivo all'inizio
poiché non esiste un unico punto di partenza evidente come la funzione main. L'enfasi
è sulla creazione di classi e oggetti che interagiscono tra loro.
1. Identificazione delle Classi
2. Definizione dei Metodi
3. Assegnazione delle Responsabilità
Attributi
Noti anche come "proprietà" o "campi", sono variabili che conservano lo stato di un
oggetto, definendo le caratteristiche specifiche di una classe. Conferiscono agli
oggetti identità e specificità, differenziandoli gli uni dagli altri. Per esempio, per una
classe Auto, gli attributi possono includere marca, modello, colore, e targa.
Metodi
Sono funzioni o procedure associate a una classe che definiscono le operazioni che
possono essere eseguite sugli oggetti di quella classe. I metodi determinano il
comportamento, ovvero "cosa l'oggetto può fare".
Esempio di classe
Oggetti
Può essere definito come un'entità discreta, con confini ben definiti che incapsula
stato e comportamento; un'istanza di una classe. Proprietà comuni a tutti gli
oggetti:
Identità: ciò che lo distingue da tutti gli altri oggetti.
Stato: viene stabilito dai valori degli attributi di un oggetto e dalle relazioni che
l'oggetto ha con gli altri oggetti in un dato istante.
Comportamento: sono le azioni che un oggetto può eseguire.
Istanziazione di classi
Istanziazione: L'atto di creare un oggetto (un'istanza) da una classe.
Costruttore: Un metodo speciale di una classe che viene utilizzato per istanziare
nuovi oggetti. Il costruttore è un metodo speciale il cui nome, in Java, coincide con
quello della classe. Un costruttore può avere 0, uno o più parametri. Non ha un
valore di ritorno, nemmeno void. Sono invocati solo in abbinamento con la keyword
new, che crea un nuovo oggetto,
Null
Il valore speciale null viene utilizzato per indicare l'assenza di un riferimento a un
oggetto in Java. È utile per gestire attributi che non sono ancora stati inizializzati o che
rappresentano dati sconosciuti. Due approcci per gestire null:
-Approccio "permissivo": Si utilizza un controllo if...else per verificare se un
attributo è null. In tal caso, si assegna un valore di default, come "sconosciuto".
-Approccio "non permissivo": Si usa il metodo Objects.requireNonNull() per
assicurarsi che un attributo non possa mai essere null. Se l'attributo è null, viene
sollevata una NullPointerException con un messaggio specifico.
CALL-BY-VALUE VS CALL-BY-REFERENCE
Call-by-Value: Significa che il metodo riceve una copia del valore passato come
parametro. Ogni modifica al parametro all'interno del metodo non influisce sulla
variabile originale. Call-by-Reference: Significa che il
metodo riceve l'indirizzo della variabile, permettendo di modificare direttamente il
valore della variabile originale
Java utilizza sempre il call by value, , il che significa che i metodi ricevono una
copia dei valori passati come parametri.
Getter e Setter
Metodi mutatori (setter):Un mutatore è un metodo che muta lo stato
dell’oggetto sul quale è invocato.
Metodi accessori (getter):Un accessore è un metodo che non muta l’oggetto sul
quale è invocato
La keyword This
Viene utilizzata all'interno di un oggetto per fare riferimento all'istanza
corrente della classe. Viene principalmente impiegata per risolvere ambiguità tra
attributi e parametri e per chiamare altri costruttori o metodi della stessa classe.
Metodi Static
Un metodo static è un metodo che non opera sugli oggetti (istanze) della classe e
non può accedere direttamente agli attributi o metodi non-static della classe. Non
hanno il parametro implicito this, perché non operano su una specifica istanza della
classe. Possono accedere solo agli attributi e metodi static della classe.
Classi interne
Una classe interna è una classe definita all'interno di un'altra classe. Questa
struttura permette di raggruppare logicamente due classi che sono strettamente
correlate. Le classi interne possono accedere ai membri della classe esterna.
Hanno accesso ai membri dell'istanza della classe esterna. Richiedono un'istanza della
classe esterna per essere create
Le classe interne possono essere dichiarate static: le classi static non possono
accedere direttamente ai membri dell'istanza della classe che le contiene.
Factory methods
I factory methods sono metodi statici utilizzati per creare oggetti. Forniscono
un'alternativa ai costruttori tradizionali e sono spesso usati per offrire maggiore
flessibilità nella creazione degli oggetti. Vantaggi: Nome del metodo personalizzabile,
Flessibilità del tipo di ritorno.
Classi Wrapper
In Java, a volte è necessario convertire un tipo primitivo (es. int, double, boolean)
in un oggetto. Ogni tipo primitivo ha una corrispondente classe wrapper che
consente di rappresentare il valore primitivo come un oggetto:
Autoboxing e Unboxing
Autoboxing: è il processo automatico con cui Java converte un valore primitivo
in un'istanza della sua corrispondente classe wrapper.
Unboxing: è il processo inverso all'autoboxing, in cui un'istanza della classe
wrapper viene automaticamente convertita nel corrispondente valore primitivo.
Main
Il metodo main è il punto di ingresso di ogni programma Java. È il primo metodo
che viene eseguito quando si avvia un programma. Caratteristiche:
Cleaner
In Java 9 è stata introdotta la classe Cleaner, che permette di registrare azioni da
eseguire automaticamente quando un oggetto non è più raggiungibile. Questo è un
approccio più sicuro rispetto a finalize().
I 3 Principi Fondamentali
-Incapsulamento: consiste nel nascondere lo stato interno e i dettagli
implementativi di un oggetto, esponendo solo un'interfaccia pubblica.
Package
Un package in Java è una namespace che organizza un insieme di classi e
interfacce correlate. I package sono utilizzati per evitare conflitti di nomi, gestire
l'accesso e mantenere una struttura di codice ordinata. Importanza dei package:
prevenzione dei conflitti, controllo dell'accesso, manutenibilità.
Import Static
In Java, è possibile importare non solo intere classi, ma anche metodi e attributi static
di una classe. Con l'import static, possiamo utilizzare i metodi e gli attributi
static della classe System senza dover scrivere System ogni volta
-Ereditarietà
Consente a una nuova classe di acquisire proprietà e comportamenti (attributi e
metodi) da un'altra classe, chiamata classe base o classe genitore. La classe
derivata o figlia può riutilizzare il codice della classe genitore e aggiungere nuove
funzionalità o modificare il comportamento esistente.
Final
In Java, il modificatore final viene utilizzato per prevenire modifiche a variabili,
metodi, e classi. Quando una classe o un metodo è dichiarato final, esso non può
essere ereditato o sovrascritto.
-Polimorfismo
Permette agli oggetti di essere trattati come istanze di diverse classi
attraverso una singola interfaccia. In altre parole, consente di definire metodi che
possono comportarsi in modo diverso a seconda dell'oggetto su cui vengono chiamati.
Attraverso Overloading e Overriding
Il metodo Equals()
Il metodo equals() di Object confronta due riferimenti per verificare se puntano allo
stesso oggetto.
Il metodo toString()
Il metodo toString() restituisce una rappresentazione testuale dell'oggetto. Di
default,Object.toString() stampa il nome della classe e l’hash code dell’oggetto.
Altri metodi di Object:
getClass(): Restituisce un oggetto Class che contiene informazioni sulla classe
dell’oggetto. hashCode(): Restituisce un valore hash dell’oggetto, utilizzato nelle
collezioni come HashMap. finalize(): Viene chiamato prima che un oggetto venga
eliminato dal garbage collector, ma è deprecato e non raccomandato.
Classi Astratte
Una classe astratta è una classe che non può essere istanziata direttamente, ma
serve come base per altre classi. Viene utilizzata per rappresentare concetti
generali che verranno specializzati nelle subclass.
Generics
La programmazione generica permette di scrivere codice che può essere riutilizzato
per oggetti di diversi tipi. I Generics introducono il concetto di tipo parametrizzato,
permettendo di generalizzare il codice per più tipi senza perdere sicurezza.
Interfacce
Un'interfaccia è un contratto che definisce un insieme di metodi che una classe
deve implementare, senza specificarne l'implementazione. Le interfacce
permettono di descrivere cosa una classe deve fare, lasciando a quest'ultima la libertà
di decidere come farlo.
Interfacce funzionali
Un'interfaccia funzionale è un'interfaccia che contiene un solo metodo astratto.
Questo metodo è l'unico che deve essere implementato quando l'interfaccia è
utilizzata.
Interfaccia comparator
Comparator è un'interfaccia che permette di definire un criterio personalizzato per
confrontare due oggetti. Si usa quando il confronto predefinito (ad esempio, l'ordine
alfabetico per le stringhe) non è adatto.
Interfaccia cloneable
L'interfaccia Cloneable indica che una classe può creare una copia di se stessa usando
il metodo clone(). Copiare un oggetto con clone() significa creare una nuova istanza
che all'inizio è identica all'originale, ma che può cambiare in modo indipendente nel
tempo.
Interfacce: metodi di default
Un metodo default è un metodo di un'interfaccia che fornisce un'implementazione
predefinita, permettendo alle classi che implementano l'interfaccia di non dover
sovrascrivere tutti i metodi.
Metodi Generici
Un metodo generico utilizza un type parameter (tipo generico), che viene
specificato al momento dell'uso. Può essere definito in una classe generica o in una
classe ordinaria (senza type parameter).
Type erasure
Il type erasure è un processo che avviene durante la compilazione e converte i tipi
generici nel loro tipo raw (grezzo). Se un tipo generico non ha bound, il tipo raw
diventa Object. Se ha un bound, il tipo raw è il primo bound indicato.
Tipi wildcard
Un tipo wildcard è un tipo generico che può variare. Si usa il carattere ? per
indicare un tipo sconosciuto
Differenza chiave; Con T: il tipo è specificato e fisso per ogni istanza della classe
generica. Con Wildcard (?): il tipo è flessibile e può variare, ma il tipo esatto non è
noto. Con Wildcard (?), possiamo lavorare con una gerarchia di tipi senza fissarne uno
preciso:
Wildcard: lettura e scrittura
Wildcard con Bound e Lettura: I wildcard con bound sono utili quando vogliamo
leggere dati senza specificare esattamente il tipo.
Wildcard e Scrittura: Tuttavia, con i wildcard non possiamo scrivere in modo
sicuro nei campi che utilizzano il tipo ? extends
Wildcard con super: Il wildcard con bound supertipo (? super T) permette di
scrivere in modo sicuro negli oggetti generici.
Wildcard senza Bound (?): Un wildcard non delimitato (?) indica che il tipo è
completamente sconosciuto e può essere di qualsiasi tipo.
?OT
Utilizziamo T quando sappiamo esattamente quale tipo useremo e vogliamo
applicare operazioni sicure di lettura e scrittura.
Utilizziamo Wildcard (?) quando vogliamo flessibilità e lavorare con gerarchie di
tipi, specialmente quando non ci interessa il tipo esatto o quando il tipo può
variare.
Cattura del wildcard
Un wildcard (?) non può essere trattato come un tipo variabile; quindi, non possiamo
usarlo direttamente per operazioni che richiedono un tipo specifico. Il metodo
swapHelper cattura il tipo wildcard con il parametro generico T e permette di
manipolare in modo sicuro i valori.
JAVA( ( Parte 2)
Stringhe
Java non ha un tipo stringa built-in. La libreria standard include una classe predefinita
chiamata String. Un oggetto di tipo String rappresenta una sequenza di caratteri
Unicode. Qualsiasi sequenza delimitata da virgolette doppie (" ") è considerata
un letterale di tipo String.
Metodi utili:
Le stringhe in Java sono immutabili: non è possibile modificare il loro contenuto dopo
la creazione. È possibile solo cambiare la variabile per riferirsi a una nuova stringa. Per
costruire stringhe dinamicamente, si utilizzano classi come StringBuilder.
Comparazione di stringhe
Due stringhe sono considerate uguali se hanno la stessa sequenza di caratteri. Regola
d’oro: Per confrontare due stringhe, utilizzare il metodo equals().
La stringa vuota ("") è una stringa con lunghezza 0. Una stringa vuota è
comunque un oggetto, con valore di lunghezza 0 e contenuto vuoto.
Var
Var è una parola chiave introdotta in Java 10 che consente al compilatore di inferire
automaticamente il tipo della variabile in base al valore assegnato.
var nomeVariabile = valore;
Regole e limitazioni: Var richiede l'inizializzazione, il tipo deve essere
determinabile, solo per variabili locali.
Classi enumeration
Un enum definisce un numero fisso di istanze; non è possibile creare nuovi
oggetti di questo tipo. Per confrontare i valori enum, si può usare l'operatore ==
poiché ogni valore enum è un'istanza singleton.
public enum Size { SMALL, MEDIUM, LARGE,
EXTRA_LARGE }
È possibile aggiungere costruttori, metodi e attributi a un tipo enumerato ma: il
costruttore di un'enumerazione è sempre privato. Metodi utili:
Classificazione delle eccezioni
Stack Trace
Uno stack trace è un elenco delle chiamate ai metodi in sospeso in un punto
specifico durante l'esecuzione di un programma. Viene generato quando
un'eccezione non gestita viene lanciata. Aiuta a individuare dove e perché si è
verificata un'eccezione. Fornisce una traccia del percorso di esecuzione che ha portato
all'errore.
Eccezioni personalizzate
Quando le eccezioni standard non descrivono adeguatamente l'errore. Allora Lancio
dell'eccezione personalizzata:
Asserzioni
Le asserzioni consentono di inserire controlli durante lo sviluppo e il testing del
programma. Possono essere facilmente disabilitate in fase di produzione, senza
modificare il codice. Sintassi:
Forma semplice: assert condition;
Forma con messaggio esplicativo: assert condition : expression;
Callbacks
Una callback è un meccanismo comune nella programmazione che consente di
specificare un'azione da eseguire in risposta a un determinato evento. In
pratica, si definisce il comportamento che deve essere attivato quando si verifica un
evento specifico.
Interazione con l'Utente: Esecuzione di un'azione quando un utente preme un
pulsante.
Eventi Temporali: Esecuzione di un'azione dopo un certo intervallo di tempo,
utilizzando la classe Timer del package javax.swing. ( Crea un timer che notifica
l'oggetto listener ogni volta che l'intervallo di tempo specificato (in millisecondi)
è trascorso.)
Lambda expression
Lambda Expressions in Java sono una funzionalità introdotta per consentire la
scrittura di codice più conciso e funzionale. Usate per esprimere
l'implementazione di un'interfaccia funzionale.
Sintassi di Base: (parametri) -> { corpo del metodo }
Generics e Container
Una classe container è una struttura che permette di memorizzare e manipolare
un insieme di oggetti. I container sono più flessibili degli array, in quanto offrono
funzionalità avanzate come l'espansione dinamica e metodi di manipolazione integrati.
L'uso di Generics con i container permette di creare contenitori che possono
memorizzare oggetti di qualsiasi tipo, mantenendo la sicurezza dei tipi a tempo di
compilazione.
Collections
Le Collections sono strutture dati che permettono di memorizzare e manipolare
insiemi di oggetti.
Una struttura dati è una classe che fornisce un modo organizzato per gestire i
dati. Le Collections sono fondamentali in qualsiasi programma che gestisca insiemi di
dati non banali.
Java include un potente Collections Framework che fornisce un insieme standard di
interfacce e classi per gestire strutture dati generiche.
Queue
L'interfaccia Queue rappresenta una coda (First-In First-Out - FIFO), dove gli
elementi vengono aggiunti alla fine e rimossi dall'inizio. Java fornisce diverse
implementazioni dell'interfaccia Queue, tra cui LinkedList, PriorityQueue, e
ArrayDeque
Interfaccia Collection
Collection è l'interfaccia base del framework delle collezioni, che fornisce metodi per
aggiungere, rimuovere e iterare su un insieme di elementi.
Interfaccia Iterator
Iterator è un'interfaccia che permette di scorrere gli elementi di una collezione
uno ad uno.
Arraylist
ArrayList è una collezione che implementa l'interfaccia List ed è basata su un
array ridimensionabile. Offre accesso sequenziale e random agli elementi tramite
indice. Ideale per scenari in cui si necessita di aggiungere o accedere frequentemente
agli elementi, meno efficiente per inserimenti o cancellazioni in mezzo alla lista.
Set
Set è una collezione che non consente duplicati. Implementazioni comuni
includono HashSet, TreeSet e LinkedHashSet.
Hashmap
HashMap è una collezione che implementa l'interfaccia Map e memorizza
elementi sotto forma di chiave-valore. Permette una ricerca efficiente dei valori
attraverso le chiavi.
Il compilatore Java
In Java, il compilatore ufficiale è javac. Trasforma il codice sorgente (.java) in bytecode
(.class), un formato intermedio che può essere eseguito su qualsiasi macchina che
abbia una Java Virtual Machine (JVM)
ARGOMENTI TEORIA
UML per il Paradigma ad Oggetti
UML
UML (Unified Modeling Language) è un linguaggio visuale di modellazione dei sistemi,
utilizzato per descrivere e progettare sistemi complessi. UML incorpora le migliori
pratiche di modellazione e ingegneria del software, adattandosi a molteplici
metodologie e approcci. Si limita a offrire una sintassi standardizzata per costruire
modelli.
Teoria di Java
Uml
UML (Unified Modeling Language "linguaggio di modellizzazione unificato") è un
linguaggio visuale di modellazione dei sistemi, utilizzato per descrivere e
progettare sistemi complessi. Incorpora le migliori pratiche di modellazione e
ingegneria del software, adattandosi a molteplici metodologie e approcci. L'obiettivo
principale di UML è quello di supportare il processo di sviluppo software
attraverso un linguaggio di modellazione comune e standardizzato. Nel 1997, UML
venne ufficialmente approvato dall’OMG come linguaggio standard per la
modellazione OO.
UML consente di modellare sistemi come insiemi di oggetti che collaborano tra
loro. Esso si divide in:
Struttura statica: rappresenta i tipi di oggetti e le relazioni tra essi
Comportamento dinamico: descrive il ciclo di vita degli oggetti e il modo in
cui interagiscono
UML è composto da diversi elementi che consentono di modellare sistemi complessi
in modo strutturato:
-Costituenti Fondamentali: Entità ( elementi che rappresentano oggetti, classi o
concetti nel sistema) Relazioni ( specificano come due o più entità sono
semanticamente correlate) , Diagrammi UML
-Meccanismi comuni
-Architettura
Diagrammi UML
UML offre tredici tipi di diagrammi che rappresentano il "cosa" e il "come" del
sistema e che possono essere suddivisi in due categorie principali:
Diagrammi della struttura statica: modellano la struttura del sistema,
mostrando le entità e le relazioni tra di esse.
Diagrammi del comportamento dinamico: descrivono come le entità
interagiscono tra loro nel tempo per eseguire funzionalità specifiche.
Inoltre, i diagrammi possono essere concreti ( rappresentano visualizzazioni
dettagliate e del sistema) o astratti (rappresentano modelli generali e concettuali) .
Non esiste un ordine rigido nella creazione dei diagrammi; essi sono strumenti per
visualizzare il modello e aggiungere informazioni ad esso. Ogni diagramma può avere
un frame che contiene informazioni sul nome, tipo e parametri del diagramma.
Meccanismi di Uml
UML prevede quattro meccanismi comuni che vengono applicati in modo uniforme:
1. Specifiche: componenti testuali che descrivono la semantica degli elementi
modellati.
2. Ornamenti: informazioni visibili nei diagrammi che arricchiscono gli elementi
del modello.
3. Distinzioni comuni: metodi diversi per ragionare sul mondo
4. Meccanismi di estendibilità: consentono di adattare UML per esigenze
specifiche tramite vincoli, stereotipi e valori etichettati
Vincoli: è una frase di testo racchiusa tra parentesi graffe che definisce
una condizione o una regola (sempre veri)
Stereotipi: variazione di un elemento di modellazione esistente che ha
la stessa forma ma un diverso scopo.
Valori etichettati: permettono di aggiungere nuove informazioni agli
elementi tramite coppie etichetta-valore.
Oggetti in UML
Un oggetto può essere definito come un’entità discreta, con confini ben definiti che
incapsula stato e comportamento; un’istanza di una classe. Gli oggetti in un sistema
orientato agli oggetti (OO) interagiscono tra loro tramite l'invio e la ricezione di
messaggi. Gli oggetti sono collegati tra loro tramite relazioni e utilizzano queste
connessioni per comunicare, formando così sistemi complessi.
In UML, gli oggetti possono essere rappresentati con vari gradi di dettaglio.
L'oggetto può essere visualizzato come un rettangolo diviso in due sezioni: una
per il nome e una per gli attributi. I nomi degli oggetti seguono la convenzione del
lowerCamelCase ( così come gli attributi e i valori).
Best practice: Mostrare solo le informazioni rilevanti per l'analisi del sistema. Ad
esempio, omettere dettagli sugli attributi se non sono necessari al fine della
rappresentazione
Una classe descrive un prototipo di oggetti con caratteristiche comuni. Ogni oggetto è
una istanza di una classe. Classificazione: una classe rappresenta un modello generale
che definisce quali attributi e operazioni ogni oggetto della classe possiede. La sua
notazione UML può variare in base al livello di dettaglio necessario, il nome
della classe è l’unica parte obbligatoria per le classi.
Sottosezione attributi
La visibilità indica chi può accedere agli attributi e alle operazioni di una
classe. (Non necessaria includerla)
Il tipo di un attributo può essere: un'altra classe (es.Persona,Indirizzo, ecc.)
un tipo primitivo (es.int,boolean,Stringin Java)
La molteplicità specifica quanti valori un attributo può contenere.
Un valore iniziale può essere assegnato agli attributi di una classe.
Sottosezione Operazioni
Le operazioni sono funzioni associate a una specifica classe. Ogni operazione
descrive un comportamento che gli oggetti di quella classe possono eseguire.
Esse hanno un nome, una lista di parametri, un tipo di ritorno.
La direzione dei parametri indica come vengono utilizzati all'interno dell'operazione, è
generalmente un dettaglio di progettazione, piuttosto che di analisi.
Ogni operazione in UML ha una proprietà chiamata isQuery.
isQuery = false (valore di default): l'operazione può modificare lo stato
dell'oggetto.
isQuery = true: l'operazione è una query che non modifica lo stato
dell'oggetto, ma si limita a leggere dati.
Ambito
L'ambito definisce se un attributo o un'operazione è specifico per ogni oggetto
(istanza) o condiviso tra tutti gli oggetti di una classe (classe). Può essere:
Ambito di istanza: Gli attributi e le operazioni sono specifici per ogni istanza
della classe
Ambito di classe: Gli attributi e le operazioni sono condivisi da tutti gli
oggetti della stessa classe
Relazioni
Le relazioni sono connessioni semanticamente significative tra elementi di un
modello. Nella programmazione OO ci concentriamo su due tipi principali di
connessioni:
Collegamenti tra oggetti: Questi collegamenti rappresentano le interazioni
dirette tra istanze di classi
Associazioni tra classi: Le associazioni rappresentano connessioni tra le classi
che modellano questi oggetti
Collegamenti
Un collegamento è una connessione dinamica tra due oggetti che consente lo
scambio di messaggi. Quando un oggetto riceve un messaggio, invoca il metodo
corrispondente alla richiesta.
Collegamenti in linguaggi OO: La realizzazione dei collegamenti varia in base al
linguaggio, ma il requisito minimo è che un oggetto abbia un riferimento all'altro.
Associazioni
Le associazioni collegano le classi, proprio come i collegamenti connettono gli
oggetti: un'associazione tra classi indica che possono esistere collegamenti tra le
istanze di queste classi.
La molteplicità specifica quanti oggetti possono essere collegati attraverso
un'associazione.
Dipendenze
Una dipendenza rappresenta una relazione tra due o più elementi del modello in cui
un cambiamento in uno di essi (detto fornitore) può influenzare o fornire
informazioni all'altro (detto cliente). Questa relazione implica che il cliente dipende
dal fornitore in qualche modo, ma non è una relazione stretta come un'associazione o
una generalizzazione. Sono utili per descrivere relazioni indirette tra gli
elementi.
È una relazione in cui una classe utilizza un'altra per eseguire determinate operazioni.
È una relazione debole, in quanto la classe ne fa uso temporaneo.
Generalizzazione
La generalizzazione è una relazione tra un elemento più generico (la
superclasse) e uno o più elementi più specifici (le sottoclassi), in cui l’elemento
più specializzato rispetta completamente l’elemento generico, ma aggiunge
informazioni o comportamenti specifici.
Nella generalizzazione, le classi vengono organizzate in una gerarchia, dove: le
sottoclassi ereditano attributi, metodi e relazioni dalla superclasse. Le sottoclassi
possono aggiungere nuovi attributi o metodi e ridefinire quelli ereditati per adattarli al
loro contesto specifico.
In UML, una classe può avere più di una superclasse diretta, il che porta a quello che
viene chiamato ereditarietà multipla. Viene spesso considerata problematica dal
punto di vista della progettazione. In Java, per evitare i problemi legati all'ereditarietà
multipla, si possono utilizzare le interfacce che consentono a una classe di
implementare più comportamenti.
Polimorfismo
Il polimorfismo si riferisce alla capacità di un oggetto di assumere diverse forme o
comportamenti, a seconda del contesto in cui viene utilizzato. In altre parole, lo stesso
metodo o funzione può comportarsi in modi differenti a seconda del tipo dell'oggetto
che lo invoca.
Interfacce in UML
Un'interfaccia è un insieme di funzionalità pubbliche, identificate da un nome, che
specificano cosa un classificatore (una classe o un componente) deve realizzare.
Possono contenere dichiarazioni di: Operazioni, Attributi, Associazioni e Vincoli.
Le interfacce in UML possono essere fornite o richieste da un classificatore:
Interfacce fornite: un classificatore offre un servizio implementando una
determinata interfaccia.
Interfacce richieste: un classificatore dipende da un'altra interfaccia per
funzionare.
Package
Un package in UML è un meccanismo per raggruppare logicamente elementi correlati
e fornire uno spazio dei nomi separato, dove i nomi degli elementi devono essere
univoci.
Un package serve a:
Fornire uno spazio dei nomi incapsulato: all'interno del package, ogni nome
deve essere unico.
Raggruppare elementi semanticamente correlati per organizzare meglio il
modello.
Definire confini semantici per separare chiaramente le diverse parti del modello.
Supportare il lavoro in parallelo e la gestione della configurazione.
Ogni elemento del modello appartiene a un solo package, e i package formano una
gerarchia ad albero, con un package radice che contiene tutti gli altri.( UML fornisce lo
stereotipo <<topLevel>> per indicare il package di livello più alto nella gerarchia.)
I package possono essere annidati all'interno di altri package, creando una gerarchia. I
package annidati hanno accesso allo spazio dei nomi dei package superiori.
Gli elementi contenuti in un package possono avere una visibilità, che determina se gli
elementi sono accessibili ai clienti esterni del package (pubblica o privata)
Una dipendenza tra package indica che un package dipende in qualche modo da un
altro, potendo usare i suoi elementi pubblici.( non i privati).
I diagrammi di sequenza
Enfatizzano la sequenza temporale degli scambi di messaggi tra diverse linee di vita. I
diagrammi di sequenza mostrano le interazioni tra linee di vita come una sequenza di
eventi ordinati temporalmente