Programmazione Java Avanzata - Slp

Programmazione Java Avanzata e Mobile
Introduzione al corso
Anno 2013/2014
Programmazione Java Avanzata e Mobile
Struttura del corso/slide:
-
Background
Hibernate
Struts
Spring (opzionale)
Android
Ogni lezione prevede la presentazione dell’argomento
dal punto di vista teorico e l’utilizzo delle conoscenze
apprese attraverso un’esercitazione
Programmazione Java Avanzata e Mobile
Testi Consigliati




Dispense delle lezioni
Java Persistence with Hibernate, Second Edition of
Hibernate in Action, Christian Bauer and Gavin King,
Manning Publications Co.
Struts 2 in Action, Donald Brown, Chad Michael Davis,
and Scott Stanlick, Manning Publications Co.
Android Developers http://developer.android.com
Si raccomanda la frequenza del corso, in modo
particolare delle esercitazioni.
Programmazione Java Avanzata e Mobile
Modalità dell’esame



L’esame consiste in una prova progettuale relativa
all’implementazione di una Web Application.
Il progetto è tipicamente svolto da gruppi di due
persone.
La discussione del progetto è effettuata solo durante il
periodo di esami.
Programmazione Java Avanzata e Mobile
Software utilizzati:

Eclipse Java EE IDE for Web Developers (cons.
Kepler)

MySQL e MySQLWorkbench (cons. 5)

Hibernate 4

Struts 2.3

Android Developer Tools (cons. v22)
Programmazione Java Avanzata e Mobile
Richiami di Java
(opzionali)
Anno 2013/2014
Richiami di base su Java
Creazione di riferimenti e instanziazione
Object o;
(crea un riferimento ad Object ma non lo istanzia)
Object o = new Object();
(alloca lo spazio in memoria)
7
Richiami di base su Java



I tipi primitivi (numerici) come int, float, double,
ecc. non sono “oggetti”. Per utilizzarli come tali
esistono le classi “wrapper” Integer, ecc.
Non esiste il concetto di puntatore, ma solo quello di
riferimento. Tutte le variabili che contengono oggetti
sono riferimenti, tranne quelle che contengono tipi
primitivi.
Non esiste il concetto di “distruttore” (per la
presenza nella VM del Garbage Collector).
8
Richiami di base su Java
Il passaggio di parametri è fissato:
per valore (tipi primitivi)
per riferimento (tipi oggetto)
Le variabili locali devono essere inizializzate prima di
essere utilizzate.
Gli attributi, se non inizializzati dal costruttore,
assumono il valore zero per i tipi numerici e null per
quelli di tipo riferimento a oggetto.
9
Programmazione Object-Oriented



Paradigma di programmazione che mette al centro la
nozione di “oggetti”, raggruppati in “classi”.
Una classe definisce un tipo di dati che rappresenta
una nozione (concreta o astratta della realtà).
Ogni oggetto è definito da un insieme di dati
(attributi) e funzioni (metodi). Gli attributi ne
rappresentano lo stato, i metodi ne modellano il
comportamento.
10
Programmazione Object-Oriented


Lo scopo principale dell’OOP è consentire il riuso
del codice attraverso la sua modularizzazione per
minimizzare la presenza di bug e accelerare i tempi
di sviluppo del software.
Caratteristiche fondamentali dei linguaggi OOP:

Incapsulamento

Ereditarietà

Polimorfismo
11
Incapsulamento




Ogni oggetto contiene sia i propri dati che le funzioni che
operano su tali dati.
L’accesso ai dati di un oggetto avviene attraverso metodi di
accesso (usando i qualificatori di accesso).
Oggetti come “scatole nere”: non sono noti i dettagli di
funzionamento, ma solo l'interfaccia.
E’ possibile cambiare l’implementazione di un oggetto
senza modificare il resto del codice.
12
Incapsulamento in Java

Qualificatori di accesso:
private
package (per default)
protected (package + sottoclassi)
public

L’incapsulamento richiede la visibilità minima
13
Ereditarietà



Estensione di una classe “base”
La classe derivata “eredita” (li vede come se fossero
i suoi) attributi e metodi (non privati) della classe
base.
La classe derivata può ridefinire attributi/metodi
della classe base o avere attributi/metodi aggiuntivi.
14
Ereditarietà in Java
Sintassi:
class Derivata extends Base


Aggiunta/overriding di attributi/metodi

Accesso ad attributi/metodi della classe Base:



uso di super
Ereditarietà “pubblica”: non è possibile ridurre l’accesso ad
attributi/metodi nella classe Derivata attraverso overriding.
Solamente ereditarietà singola.
15
Ereditarietà in Java




Esempio:
public class Studente extends Persona
Studente può aggiungere attributi (es. matricola) o
metodi - es. getMatricola()
Studente può ridefinire
- es. void print()
metodi
di
Persona
16
Polimorfismo



Permette di avere metodi con la stessa signature che
si comportano in modo differente a seconda degli
oggetti su cui vengono invocati.
Polimorfismo ed ereditarietà: uso di metodi che
accettano in input il super-tipo ma il cui
comportamento si adatta ai sotto-tipi.
Late binding – la scelta del metodo corretto avviene
a run-time e non a compile-time.
17
Classi Astratte in Java


Classi in cui alcuni metodi sono astratti (non sono
implementati, c’è solo la signature).
Sintassi:
public abstract class FiguraGeometrica {
public abstract double perimetro();
…}


Non è possibile istanziare oggetti di una classe astratta. E’
possibile dichiarare riferimenti di tipo “astratto”.
Per istanziare oggetti è necessario derivare una classe che
implementa tutti i metodi astratti.
18
Classi Astratte in Java

Esempio:
public class Quadrato extends FiguraGeometrica
{
public double perimetro(){
return misuraLato*4;
}
…
}


E’ possibile istanziare oggetti di Quadrato solo se tutti i
metodi astratti ereditati sono implementati.
E’ possibile inizializzare un riferimento FiguraGeometrica
con un oggetto Quadrato (subtyping).
19
Interfacce in Java



Simili alle classi astratte, ma possono contenere solo
signature di metodi (pubblici) senza implementazione.
Servono a “forzare” una classe a implementare un’insieme
di metodi. I metodi sono pubblici per default.
Sintassi:
public interface FiguraGeometrica {
public double perimetro();
…
}

Non è possibile istanziare oggetti di una interfaccia. E’
possibile dichiarare riferimenti di tipo “interfaccia”.
20
Interfacce in Java

E’ possibile istanziare oggetti di una classe che implementa
quell’interfaccia.
Sintassi:
public class Quadrato implements FiguraGeometrica {
public double perimetro(){
return misuraLato*4;
}
…
}
21
Eccezioni controllate e non

Eccezioni controllate:




Il compilatore controlla che noi non le ignoriamo
dovute a circostanze esterne che il programmatore non
può evitare
Es. FileNotFoundException
Eccezioni non controllate:

rappresentano un errore del programmatore

Es. ArrayIndexOutOfBoundsException
Gestione delle Eccezioni
Due Possibilità:
1. Catturare l’eccezione

blocchi try / catch
2. Dire al compilatore che vogliamo terminare il metodo
quando si verifica l’eccezione.

Usare throws
Enunciato finally

Per eseguire task che devono essere comunque
completati (sia in presenza che in assenza di errori, es.
chiusura file)
Programmazione Java Avanzata e Mobile
Nozioni aggiuntive di Java
Anno 2013/2014
Nozioni aggiuntive di Java

Convenzioni sui nomi

Programmazione generica

Annotations

Serializzazione

Logging
25
Convenzioni
I nomi delle classi sono sostantivi che iniziano in
maiuscolo
Es. class
Studente{ … }
I nomi delle istanze iniziano con lettera minuscola
Es. Studente
studente=new Studente();
Tutte le variabili (locali) devono essere inizializzate
prima di essere utilizzate.
Es. void
contaRipetizioni (){
int cont=0;
…
26
Convenzioni
Se il nome è composto da più di un sostantivo, ognuno
di questi avrà l'iniziale maiuscola
Es. class
StudenteLavoratore{ ... }
I nomi dei metodi sono composti da un verbo, oppure
un verbo + sostantivo; solo la prima iniziale è
minuscola
Es. int
getRicaviEsercizio()
I nomi delle variabili membro sono composti da
sostantivi e usano la stessa convenzione dei metodi
Es. int
annoIscrizione
27
Convenzioni
I metodi di accesso sono relativi agli attributi:
Es. int
getMatricola() …
Es. void
setMatricola(int matricola) …
Per gli attributi booleani si utilizza la forma ‘is’
Es. boolean
isReady()
28
Convenzioni
Le costanti sono tutte in maiuscolo, con i sostantivi
separati da underscore
Es. final
int MAX_VOTO = 30
I nomi dei package sono tutti in minuscolo, con i
sostantivi separati da underscore
Es. package
ing.programmazione_java_avanzata
L’organizzazione in package è un elemento molto
importante
29
Programmazione Generica
Tecnica di programmazione per cui è possibile
realizzare strutture dati e algoritmi che funzionano con
diversi tipi di dati.
public class ArrayList<T> {
public ArrayList() {...}
public void add(E element) {...}
...
}
Usata in questo modo:
ArrayList<String> listaNomi = new ArrayList<String>();
30
Programmazione Generica
Collection rappresenta il concetto di gruppo di oggetti
(duplicati o no, ordinati o no, con priorità, …)
31
Programmazione Generica
Per cui potrei:
Set insieme=new HashSet();
Element e=new Element();
Insieme.add(e);
Gli elementi possono essere di diverso tipo.
E’ necessario un cast in fase di accesso in lettura.
E’ preferibile parametrizzare.
Set<Element> insiemeElementi=new HashSet<Element>();
32
Java Annotations




Dalla versione 5.0 Java ha introdotto dei meccanismi
per inserire metadati descrittivi nel codice stesso
Questi metadati (dati a proposito dei dati) possono
essere usati per rendere espliciti alcuni
comportamenti
Sono immersi nel codice ed esistono analizzatori in
grado di adoperarli per semplificare il lavoro si
sviluppo o potenziare il Design By Contract Es.
@Override, @Deprecated, @SuppressWarnings
Molti framework definiscono annotation proprie
33
Serializzazione





La Serializzazione, in Java, è la trasformazione di un
oggetto nella sua rappresentazione binaria
Un oggetto serializzato può essere salvato su disco,
su database, inviato via internet etc
Gli oggetti, per essere serializzabili, devono
implementare l'interfaccia Serializable
Ogni oggetto serializzabile deve avere una variabile
membro serialversionUID
È una sorta di hash che serve a controllare che non
vengano deserializzati oggetti di versioni diverse 34
Serializzazione
serialversionUID
può
essere
gestita
o
meno
dal
programmatore.
Tipicamente abbiamo:
public class Utente implements Serializable {
private static final long serialVersionUID = 1L;
…
}
35
Logging
Nella fase di testing o di debugging può essere utile
evidenziare il verificarsi di situazioni particolari:
public class Esame {
private int voto;
…
void setVoto(int voto){
if (voto > 30)
System.out.println(“Errore …”);
this.voto=voto;
}
…
36
Logging
L'output su console (System.out.println) non è
una soluzione ideale in quanto:
- La console deve essere tenuta sotto controllo da una
persona competente
- Per salvare l'output dobbiamo realizzare script al di
fuori del nostro programma
- Tutto l'output viene inviato nello stesso luogo: non
c'è modo di separare per priorità o per sottosistema
37
Logging
Un Log è un file di testo che raccoglie l'output da un
programma
È usato normalmente per segnalazione e per debug
(es. server)
Si vogliono raccogliere dati sull'uso ed il
comportamento di determinati oggetti
Si vuole avere un resoconto delle funzioni eseguite
38
Apache Log4J 2
È una libreria usata nei progetti Java
È ormai uno standard de facto per il logging
La seconda versione (Log4J 2) ha migliorato
performance, funzionalità e affidabilità ma non è
compatibile con la precedente
(http://logging.apache.org/log4j)
Le librerie minime da usare sono log4j-api e
core (attualmente log4j-api-2.0-beta9.jar e
core-2.0-beta9.jar)
log4jlog4j39
Apache Log4J 2
E’ utile includere i JavaDoc
Definisce diversi livelli di log a seconda della gravità:
FATAL, ERROR, WARN, INFO, DEBUG,
TRACE
Un file di configurazione (XML o JSON) ci permette
di scegliere la destinazione dei nostri log, cosa loggare
e il formato del log.
40
Apache Log4J
public class ProvaLog4J {
private static Logger logger =
LogManager.getLogger("Nome del logger");
public static void main(String[] args){
logger.fatal("Esempio di log fatal");
logger.error("Esempio di log error");
logger.info("Esempio di log info");
}
}
41
Apache Log4J 2
File log4j2.xml (nel classpath – in src)
<?xml version="1.0" encoding="UTF-8"?>
<configuration status="OFF">
<appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %5level %logger{36} - %msg%n"/>
</Console>
</appenders>
<loggers>
<root level="all">
<appender-ref ref="Console"/>
</root>
</loggers>
42
</configuration>
Apache Log4J 2
Esercitazione 1
43
Programmazione Java Avanzata e Mobile
PATTERN
Pattern

Una soluzione progettuale generale a un
problema ricorrente

Elementi per il riuso di software ad oggetti

Vantaggiosi e ‘’obbligatori’’ da usare
Pattern
Un pattern è caratterizzato da:




Nome - rappresentativo del pattern stesso
Problema - la situazione (o condizione) alla
quale si può applicare il pattern
Soluzione – la configurazione degli elementi
adatta a risolvere il problema
Conseguenze, vantaggi (risultati) e svantaggi
(vincoli) che derivano dall'applicazione del
pattern
Pattern
Importanti sono le conseguenze:
Esse comprendono considerazioni di tempo e di
spazio, possono descrivere implicazioni del
pattern con alcuni linguaggi di programmazione e
l'impatto con il resto del progetto
Pattern
Il pattern Singleton
Pattern - Singleton
Semplice da presentare e implementare (in
Java), risulta molto utilizzato
Nome: Singleton
Problema: assicurare che per una determinata
classe esista un’unica istanza attiva.
Utile nel caso in cui si abbia la necessità di
centralizzare informazioni e comportamenti in
un’unica entità condivisa da tutti i suoi utilizzatori.
Es. Spooler di stampa
Pattern - Singleton
Soluzione: associare alla classe stessa la
responsabilità di creare le proprie istanze.
Conseguenze:
• accesso controllato alla singola istanza;
• possibilità di usare un numero variabile di
istanze;
• una maggiore flessibilità (es. posso modificare i
dati gestiti dal singleton senza invalidare l’unicità
dell’istanza)
Pattern - Singleton
Implementazione in Java:
public class Gestore {
private static Gestore gestore = null;
private Gestore() {}
public static synchronized Gestore getGestore() {
if (gestore == null)
gestore = new Gestore();
return gestore;
}
}
Pattern - Singleton
Controllo dell’unicità:
public static void main(String[] args) {
Logger l = LogManager.getLogger("Test");
Gestore g1=Gestore.getGestore();
l.info(g1.toString());
Gestore g2=Gestore.getGestore();
l.info(g2.toString());
}
Pattern
Il pattern DAO
(Data Access Object)
Pattern - DAO
Nome: DAO
Problema: disaccoppiare l’accesso ai dati
rispetto alla sua memorizzazione sottostante.
Es. i metodi create(…),
read(…), update(…), delete(…)
usati per la persistenza dei dati (CRUD)
andrebbero tutti modificati al cambiare della
sorgente dei dati (passo da Oracle a MySQL)
Pattern - DAO
Soluzione: sposto la logica di accesso ai dati
all’oggetto DAO che indica quali funzionalità sono
supportate nascondendo la sorgente
Conseguenze:


portabilità delle applicazioni da una sorgente di
dati ad un’altra
posso iniziare l’implementazione senza dovermi
occupare di quale sia la sorgente dei dati
Pattern - DAO
Implementazione in Java:
scaricare esercitazione Dao
Pattern
Il pattern Factory
(Factory Method)
Pattern - Factory
Nome: Factory
Problema: creare oggetti senza specificare
(esplicitamente) la classe specifica a cui gli
oggetti appartengono.
Soluzione: definire metodi ad hoc (factory) per la
creazione degli oggetti.
Conseguenze: rende completamente
interscambiabili le implementazioni che
soddisfano un’interfaccia
Pattern - Factory
Implementazione in Java:
esercitazione Factory (Factory con Singleton)
public class UtenteDAOFactory {
private static UtenteDAO utenteDao = null;
private UtenteDAOFactory(){}
public static UtenteDAO getDAO() {
if (UtenteDao == null ) {
utenteDao = new UtenteDAOSimpleImpl();
}
return utenteDao;
}
}
Pattern - Factory
Passi aggiuntivi
- Modifico istanziazione del DAO
(lo chiedo al Factory)
UtenteDAO utenteDao = UtenteDAOFactory.getDAO();
- Modifico visibilità del costruttore dei DAOImpl
protected UtenteDAOSimpleImpl(){};
-
Pattern
Il pattern MVC
(separazione delle responsabilità)
Pattern - MVC
Scheda (molto) sintetica
Nome: MVC (Model-Control-View)
Problema: manutenibilità del codice (vedi
prossime slide)
Soluzione: suddivisione del codice in tre ‘’classi’’
distinte (vedi prossime slide)
Conseguenze: promuove il riuso del codice,
consente lo sviluppo del codice in parallelo,
facilita l’implementazione di nuove funzionalità, e
molte altre cose positive …
Pattern - MVC
Problema a cui si applica: esempio
Consideriamo un sito e le pagine per gestire
l’autenticazione di un utente.
Una pagina risponde alla richiesta di login,
elabora i dati, memorizza delle informazioni, e
mostra il risultato della procedura (autorizzato o
no).
Una modifica ad una delle funzionalità sopra
coinvolge tutte le altre funzionalità.
Esempio
Esempio: Vincoli



Gli stessi dati aziendali devono essere presentati in
più modi: HTML, WML, JFC/Swing, XML.
Gli stessi dati aziendali devono essere aggiornati a
seguito di differenti tipi di interazione: uso di link su
una pagina HTML o WML, uso di pulsanti su una GUI
JFC/Swing, uso di messaggi SOAP scritti in XML.
Supportare molteplici tipi di presentazioni (view) ed
interazioni non deve avere impatto sui componenti
Problemi/1

Il mix fra il codice che riguarda la logica
dell’applicazione (login, inserimento informazioni, ecc.) e quello che riguarda la presentazione
dei risultati (HTML, XML, …) causa:


Duplicazione di codice (relativo alla logica) in ogni
nuova interfaccia (presentazione) che viene
aggiunta all’applicazione.
Difficoltà nel debug del codice e nella manutenzione.
Problemi/2



Difficoltà nel mantenere costante la logica al variare
della presentazione (presentazione  logica).
Se in futuro cambia la logica, si devono operare
tante modifiche per quante volte essa è ripetuta nei
moduli di presentazione (logica  presentazione).
L’implementazione di una pagina richiede
competenze estese (Java, HTML, XML, SOAP, …)
Soluzione: Model-View-Controller



Model. Si occupa solo dei dati utili all’applicazione e fornisce i
metodi per accedere ad essi.
View. Si occupa solo della gestione dell’interfaccia utente. Non
si
preoccupa
della
logica
applicativa
o
dell’elaborazione/validazione
dell’input.
Garantisce
che
l’interfaccia rifletta lo stato corrente del modello.
Controller. Si occupa soltanto di validare/elaborare l’input
dell’utente (fornito dalla parte View) e tradurlo in aggiornamenti
(messaggi) che vengono passati al modello. Non si occupa di
come sia ricevuto l'input (interfaccia) o di che cosa faccia il
modello con questi aggiornamenti.
Soluzione: Model-View-Controller
Flusso di controllo MVC
Model
submit form
Controller
View
14
Pattern MVC
Responsabilità del Model:



Il model memorizza i dati e fornisce del metodi
specifici per l’applicazione per definire i valori di
questi.
I metodi di gestione dei dati non sono generici. Sono
personalizzati per l’applicazione e devono essere noti
al controller e alla view.
Il model deve anche fornire alle view un modo con cui
queste possono registrarsi e annullare la loro
registrazione. In tal modo, se determina che il suo
stato è cambiato, deve inviare una notifica a tutte le
viste registrate.
Pattern MVC
I dati potrebbero essere ovunque:
File locale, File remoto, DBMS Oracle, DBMS MySQL,
…
Se sono su un DBMS, possiamo utilizzare Hibernate per
implementare il Model.
Hibernate facilita la memorizzazione (persistenza) e
gestione di oggetti Java associati a relazioni di un
DBMS.
La suddivisione dell’applicazione in package dovrebbe
rispecchiare l’implementazione del pattern MVC
Pattern
Il pattern
Inversion Of Control
(opzionale)
Pattern - IoC
Nome: Inversion Of Control
Problema: la dipendenza tra le classi
Il principio della separazione delle responsabilità
(MVC) porta all’esplosione del numero delle
classi (ognuna specializzata su una particolare
responsabilità). Le classi arrivano ad accumulare
dipendenza da decine di altre classi.
Le istanze per essere inizializzate richiedono di
crearne altre, e queste ancora altre, e così via
Pattern - IoC
Conseguenze delle dipendenze (RFI):
1. E’ complicato modificare una classe perchè
tale cambiamento coinvolge altre classi
(Rigidità)
2. Effettuando una modifica ad una classe,
un’altra parte del sistema smette di funzionare
(Fragilità)
3. E’ complicato riutilizzare moduli di
un’applicazione perchè prima devono essere
“sganciati” dal resto del codice (Immobilità)
Pattern - IoC
Esempio:
public Class OggettoA { …}
public Class OggettoB {
private OggettoA a;
OggettoB (){
this.a=new OggettoA(…);
}
…
}
OggettoB dipende da OggettoA
Il costruttore genera un forte accoppiamento tra
le classi
Pattern - IoC
Principi alla base della soluzione:
1. I moduli di alto livello non devono dipendere da
quelli di basso livello: entrambi dovrebbero
dipendere solo da astrazioni (interfacce)
2. Le astrazioni non dovrebbero dipendere dai
moduli di basso livello, questi ultimi dovrebbero
dipendere dalle astrazioni.
Pattern - IoC
Dependency Injection come soluzione:
Es. Construction Injection - la dipendenza viene
iniettata tramite l'argomento del costruttore
public Class OggettoB {
private OggettoA a;
OggettoB (OggettoA a){
this.a=a;
}
…
}
Es. Setter Injection - la dipendenza viene iniettata
attraverso un metodo "set"
Pattern
Il pattern Decorator
(opzionale)
Pattern - Decorator
Nome: Decorator
Problema: aggiungere funzionalità (Decorazioni)
ad una classe (Component) a run-time
Soluzione: - Definire un'interfaccia (astrazione)
del Component, che le classi concrete
implementano
Definire una classe (Decorator) che rappresenta l
a decorazione, implementa l'interfaccia
Component e contiene l’oggetto che decora
Pattern - Decorator
Gelato (Componente), Decorazioni (panna,
3_gusti, max, …)
public interface Gelato {
public double getPrezzo();}
public class GelatoBase implements Gelato {
public double getPrezzo() {return 1;}
}
abstract public class GelatoDecorator implements Gelato {
private Gelato decoratedGelato;
public GelatoDecorator(Gelato decoratedGelato) {
this. decoratedGelato = decoratedGelato; }
public double getPrezzo() {
return decoratedGelato.getPrezzo();
}
}
Pattern - Decorator
public class ConPanna extends GelatoDecorator {
public conPanna(Gelato decoratedGelato) {
super(decoratedGelato);
}
public double getPrezzo() {
return super.getPrezzo() + 0.2;
}
}
public class Max extends GelatoDecorator {
public Max(Gelato decoratedGelato) {
super(decoratedGelato);
}
public double getPrezzo() {
return super.getPrezzo() + 0.7;
}
}
…
Pattern - Decorator
Gelato g = new GelatoBase();
System.out.println(“Prezzo: " + g.getPrezzo());
g = new conPanna(g); //Gelato con panna
System.out.println(“Prezzo: " + g.getPrezzo());
g = new Max(g); //Gelato Max con Panna
System.out.println(“Prezzo: " + g.getPrezzo());
…