Introduzione ai design pattern - PowerPoint PPT Presentation

About This Presentation
Title:

Introduzione ai design pattern

Description:

Introduzione ai design pattern Cosa sono i design pattern I problemi incontrati nello sviluppare grossi progetti software sono spesso ricorrenti e prevedibili. – PowerPoint PPT presentation

Number of Views:94
Avg rating:3.0/5.0
Slides: 44
Provided by: libe201
Category:

less

Transcript and Presenter's Notes

Title: Introduzione ai design pattern


1
Introduzione ai design pattern
2
Cosa sono i design pattern
  • I problemi incontrati nello sviluppare grossi
    progetti software sono spesso ricorrenti e
    prevedibili.
  • I design pattern sono schemi utilizzabili nel
    progetto di un sistema
  • Permettono quindi di non inventare da capo
    soluzioni ai problemi gia risolti, ma di
    utilizzare dei mattoni di provata efficacia
  • Inoltre, un bravo progettista sa riconoscerli
    nella documentazione o direttamente nel codice, e
    utilizzarli per comprendere in fretta i programmi
    scritti da altri
  • forniscono quindi un vocabolario comune che
    facilita la comunicazione tra progettisti

3
Design pattern nella libreria Java
  • I pattern sono utilizzati pervasivamente dalle
    classi standard di Java, e sono alla base della
    progettazione orientata agli oggetti
  • Es. Iterator fornisce un modo efficiente e
    uniforme per accedere a elementi di collezioni
  • Altri esempi presentati in queste slide
  • Abstract Factory, Singleton, Flyweight, State,
    Strategy, Proxy, Adaptor e Decorator

4
Abstract Pattern
  • Costruire implementazioni multiple di una stessa
    classe
  • Es. Poly densi e sparsi
  • DensePoly una implementazione di Poly adatta al
    caso in cui ci sono pochi coefficienti nulli (ad
    es. quella vista per i Poly con un array per
    tutti i coefficienti)
  • SparsePoly una diversa implementazione,
    efficiente quando molti coefficienti sono nulli
    (es. lista a puntatori, in cui ogni nodo
    memorizza il coeff. e il grado di ogni termine
    !0).
  • Poi però se Dense e Sparse sono tipi distinti
    dovremmo definire codice diverso per ogni
    polinomio
  • public static void DensePoly derivata (DensePoly
    p)
  • public static void SparsePoly derivata
    (SparsePoly p)
  • ma differenza fra Dense e Sparse è solo
    implementativa

5
Poly Astratta e impl. multiple
  • Soluzione definire una classe Poly e definire
    DensePoly e SparsePoly come sue estensioni (pure)
  • Utilizzatore di Poly vede solo i metodi
    definiti in Poly.
  • //_at_ ensures ( \result derivata di p )
  • public static Poly derivata(Poly p)
  • Non importa se a runtime p sarà un DensePoly o
    uno SparsePoly.
  • Poly non contiene un rep (perche non vi molto in
    comune fra le due implementazioni) saranno
    sottoclassi a stabilire modalità di
    memorizzazione
  • Quindi Poly deve diventare astratta non è
    possibile fare add, ecc. senza il rep. Gerarchia
    di tipi può essere utilizzata per fornire più
    implementazioni dello stesso tipo
  • Il tipo da implementare è di solito descritto con
    interfaccia (se nessuna operazione è
    implementabile) o classe astratta (se alcune
    operazioni sono implementabili)

6
Creazione di oggetti?
  • Il codice di un programma orientato agli oggetti
    non dipende dalla precisa classe cui appartiene
    un certo oggetto. I programmi richiedono a un
    oggetto solo il rispetto del contratto
    corrispondente alla sua specifica (il suo tipo)
  • Limitare le dipendenze dalle classi è
    desiderabile perché permette di sostituire
    unimplementazione con unaltra. es si può usare
    Poly e poi se si passa una DensePoly o una
    SparsePoly tutto funziona lo stesso
  • Eccezione le chiamate ai costruttori il codice
    utente che chiama il costruttore di una
    determinata classe rimane vincolato a quella
    classe
  • Ci piacerebbe potere lasciare alla classe Poly
    stessa la scelta se il tipo da costruire e' uno
    SparsePoly o un DensePoly!

7
Factory Method
  • La soluzione è nascondere la creazione in un
    metodo detto factory restituisce un oggetto di
    una classe senza essere costruttore di quella
    classe
  • Esempio il metodo che restituisce loggetto
    iteratore associato a un contenitore (nella
    nomenclatura Liskov, oggetti generatori) e un
    esemplare di una classe che implementa
    linterfaccia Iterator, ma il metodo non e un
    costruttore
  • In Java le chiamate ai costruttori non sono
    personalizzabili. Una factory può invece
    scegliere la strategia di allocazione.

8
Factory (2)
  • Il metodo può creare oggetti di classi diverse a
    seconda dei parametri, ma tutti questi oggetti
    avranno lo stesso tipo.
  • Esempio un polinomio del tipo axnb viene
    implementato da una classe SparsePoly, mentre il
    polinomio generico è un esemplare di
    DensePoly.public static Poly createPoly (int
    a) int degree -1, numCoeffs 0 for (int
    n 0 n lt a.length n) if (an ! 0)
  • numCoeffs degree n if
    ((numCoeffs 2 a0 ! 0) numCoeffs
    1) return new SparsePoly (degree, adegree,
    a0) return new DensePoly (degree, a)

9
Alternativa Factory Class
  • A volte e' preferibile che il metodo statico sia
    in una classe a parte
  • Es. public class FabbricaDiPoly public static
    Poly createPoly (int a) ...
  • Ad es. puo' essere comodo per aggiungere
    operazioni che influenzano che cosa si vuole
    fabbricare o per non consentire la costruzione di
    oggetti di tipo Poly a chi vede solo la classe
    Poly

10
Abstract Factory
  • La soluzione non è ottimale dal punto di vista
    dell'estendibilita' cosa succede se aggiungiamo
    una classe PolyMezzoDenso che implementa un Poly
    per i casi intermedi ne' densi ne' sparsi?
  • Dobbiamo modificare il metodo factory, violando
    principio Open/Closed.
  • Allora si può usare Abstract Factory
  • La Factory Class è astratta il metodo factory e'
    astratto
  • C'e' un'erede concreta della Factory per ogni
    classe concreta dell'implementazione, che
    implementa il metodo giusto (FactoryDensePoly,
    FactorySparsePoly)
  • Estendendo la classe Poly con PolyMezzoDenso ci
    basta aggiungere una FactoryPolyMezzoDenso

11
Abstract Factory descritto in UML
12
Pattern per Ottimizzazioni comuni
  • Alcuni pattern forniscono trucchi semplici e
    funzionali per velocizzare un programma o ridurne
    i requisiti di memoria.
  • A volte lutilizzo di questi pattern non fa parte
    del progetto vero e proprio del sistema, ma un
    programmatore competente sa riconoscere le
    occasioni in cui usarli efficacemente

13
Singleton
  • A volte una classe contiene per definizione un
    solo oggetto
  • e.g., una tabella, un archivio in cui si assume
    che ogni elemento sia individuato univocamente
    dal suo identificatore (quindi se ci fossero piu
    tabelle non si avrebbe questa garanzia di
    unicità)
  • Usare una normale classe con soli metodi statici
    non assicura che esista un solo esemplare della
    classe, se viene reso visibile il costruttore
  • In una classe Singleton il costruttore e
    protetto o privato
  • Un metodo statico, o una factory, forniscono
    laccesso alla sola copia delloggetto

14
Singleton pattern il tipico codice
  • public class SingletonClass
  • private static SingletonClass s //the single
    instance
  • public static SingletonClass getObject()
  • //build the unique object only if it does not
    exist already
  • if (s null) s new SingletonClass()
  • return s
  • private SingletonClass() // the constructor
  • // other methods

15
Flyweight
  • Quando molti oggetti identici (e immutabili)
    vengono utilizzati contemporaneamente, e utile
    costruire solo un oggetto per ogni classe di
    equivalenza di oggetti identici
  • gli oggetti condivisi vengono chiamati flyweight
    (pesi mosca) perche spesso sono molto piccoli
  • Questo pattern va ovviamente usato solo se il
    numero di oggetti condivisi e molto elevato
  • Gli oggetti flyweight devono essere immutabili
    per evitare problemi di aliasing

16
Flyweight implementazione del pattern
  • Occorre una tabella per memorizzare gli oggetti
    flyweight quando vengono creati
  • Non si possono usare i costruttori
  • un costruttore costruisce sempre una nuova
    istanza!
  • naturale usare una factory class per creare gli
    oggetti
  • la factory deve controllare se loggetto
    richiesto esiste già nella tabella prima di
    crearlo se non esiste, chiama un costruttore
    (privato!), altrimenti restituisce un reference
    alloggetto esistente.
  • Se necessario, occorre rimuovere gli oggetti
    dalla tabella quando non sono più utilizzati
  • Efficiente usare questo pattern se cè un alto
    grado di condivisione degli oggetti
  • si risparmia memoria
  • non si perde tempo a inizializzare oggetti
    duplicati
  • si può usare per il confronto al posto di
    equals.

17
UML per Flyweight
18
Esempio di pattern flyweight
  • classe Word per rappresentare parole immutabili
    in applicazioni di elaborazione testi
  • Public class Word
  • //OVERVIEW Words are strings that provide
  • //methods to produce them in various forms words
    are immutable for
  • // each unique string there is at most one word
  • private static Hashtable t //maps strings to
    words
  • public static makeWord(String s) //factory
    returns the word for string s
  • private Word(String s) //constructor of the
    unique word for string s
  • public String mapWord(Context c)
  • //returns the string corresponding to this in the
    form
  • // suitable for context c
  • // other word methods

19
State
  • A volte si vuole usare un'implementazione diversa
    dello stesso oggetto durante la sua vita
  • per esempio, una classe vettore può usare una
    rappresentazione diversa a seconda del numero
    degli elementi. Se si usa una sola classe il
    codice degli oggetti mutabili può diventare assai
    complicato e pieno di condizionali
  • Razionalizzazione della struttura del codice gli
    oggetti cambiano configurazione a seconda dello
    stato in cui si trovano. Il pattern State
    introduce un ulteriore strato tra il tipo
    implementato e limplementazione
  • a un unico tipo si fanno corrispondere piu
    classi che lo implementano, e che corrispondono a
    diversi stati in cui possono trovarsi gli
    esemplari del tipo
  • nel corso della vita delloggetto, possono essere
    utilizzate diverse implementazioni senza che
    lutente se ne accorga

20
State (2)
  • Implementazione del pattern
  • Si crea uninterfaccia o una classe astratta che
    rappresenta le parti delloggetto che possono
    essere sostituite nel corso della vita
    delloggetto
  • Ciascuna delle possibili rappresentazioni (stati)
    diventa unimplementazione dellinterfaccia o un
    erede della classe astratta
  • La classe principale conterrà il codice per
    scegliere la rappresentazione più adatta e per
    delegare limplementazione alla sottoclasse
    piuappropriata per lo stato delloggetto

21
Esempio di State
  • Classe BoolSet, analogo dellIntset un insieme
    di boolean che cambia implementazione a seconda
    del numero di elementi si usano due classi
    SmallBoolSet e BigBoolSet a seconda della
    cardinalità dellinsieme
  • interface BoolSetState
  • public boolean get (int n)
  • throws IndexOutOfBoundsException
  • public BoolSetState set (int n, boolean val)
  • throws IndexOutOfBoundsException
  • public class BoolSet
  • BoolSetState s
  • public BoolSet () BoolSetState new
    SmallBoolSet ()
  • public final boolean get (int n)
  • throws IndexOutOfBoundsException return
    s.get (n)
  • public final void set (int n, boolean val)
  • throws IndexOutOfBoundsException s s.set
    (n, val)

22
Esempio di State (2)
  • SmallBoolSet usa un singolo long per implementare
    set i cui elementi sono tutti minori di 64.
  • class SmallBoolSet implements BoolSetState
  • public static final long MAX_SIZE 64
  • long bitset
  • public boolean get (int n)
  • throws IndexOutOfBoundsException
  • if (n lt 0)
  • throw new ArrayIndexOutOfBoundsException(n)
  • return n lt MAX_SIZE (bitset (1 ltlt n)) !
    0

23
Esempio di State (3)
  • Se si imposta a 1 un elemento oltre il 64-esimo,
    viene creato un BigBoolSet.
  • public BoolSetState set (int n, boolean val)
  • throws IndexOutOfBoundsException
  • if (n lt 0)
  • throw new ArrayIndexOutOfBoundsException(n)
  • if (val)
  • if (n gt MAX_SIZE)
  • return new BigBoolSet (this).set (n,
    val)
  • bitset (1 ltlt n)
  • else if (n lt MAX_SIZE)
  • bitset (1 ltlt n)
  • return this

24
Esempio di State (4)
  • Per la classe BigBoolSet vediamo solo il metodo
    che
  • costruisce un BigBoolSet a partire da uno
    SmallBoolSet
  • class BigBoolSet implements BoolSetState
  • ...
  • public BigBoolSet (SmallBoolSet s)
  • for (i 0 i lt s.MAX_SIZE i)
  • if (s.get (i))
  • set (i, true)
  • ...

25
Procedure come oggetti
  • Java non permette di utilizzare come oggetti le
    chiamate a un metodo
  • Questo, tuttavia, può essere utile per definire
    astrazioni altamente generiche ed estendibili
    (pluggable)
  • Lunico modo di ottenere questo risultato è
    definire classi o interfacce molto piccole.Ci
    sono esempi nella libreria di classi di Java
  • Comparable
  • Runnable
  • ActionListener

26
Strategy
  • Il pattern Strategy fornisce un oggetto che
    compie unoperazione precisa, richiesta
    dallesterno
  • Per esempio, stabilire un ordinamento tra oggetti
  • Loperazione è esprimibile con clausole Requires
    e Ensures
  • Un esempio di questo pattern nellinterfaccia
    Comparator di JDK 1.4

27
UML
28
Esempio di Strategy ordinamento di oggetti
qualunque
  • Vogliamo ordinare un contenitore di oggetti
    (p.es. un array)
  • La procedura di ordinamento è sempre la stessa
    per tutti i tipi di oggetti possibili
  • vorremmo quindi fare un unico metodo per tutti i
    tipi. Qualcosa come
  • public static void sort(Object s
  • //_at_ensures ( s è ordinato )
  • ma serve un modo per confrontare gli elementi
    in s! Object non ha un metodo per il confronto e
    quindi occorre definirlo da qualche altra parte
  • Idea aggiungo come argomento al metodo un
    oggettino incaricato del confronto.
  • Per potere rendere il metodo sort applicabile a
    ogni tipo, loggetto sarà di tipo interfaccia.
    Quindi
  • definisco l'interfaccia Comparator (esiste
    peraltro in java.util), che definisce
    sintatticamente il confronto di due oggetti
  • fornisco una implementazione di Comparator per il
    tipo che voglio ordinare (es. IntegerComparator)
  • Passo anche un Comparator quando chiamo la
    procedura per confrontare gli elementi

29
Interface Comparator
  • interface Comparator //OVERVIEW immutabile
    public int compare (Object o1, Object o2)
  • throws ClassCastException, NullPointerException
  • /_at_ensures ( se o1 e o2 non sono di tipi
    confrontabili
  • _at_ lancia ClassCastException
  • _at_ altrimenti o1lto2 ? ret 1
  • _at_ o1o2 ? ret 0
  • _at_ o1gto2 ? ret 1
  • NB
  • interfaccia non è supertipo dei tipi i cui
    elementi vanno comparati!

30
metodo sort
  • Argomento aggiuntivo un oggetto di tipo
    Comparator (uno solo per tutti gli elementi!).
  • Esempio da java.util.Arrays
  • public static void sort (Object a, Comparator
    c)
  • if (c.compare(a.i, a.j)
  • Es. di uso
  • public class AlphabeticComparator implements
    Comparator public int compare(Object o1, Object
    o2) String s1 (String)o1 String s2
    (String)o2 return s1.toLowerCase().compareTo(
    s2.toLowerCase())
  • ...String s new String30 ...
  • Java.util.Arrays.sort(s, new AlphabeticComparator(
    )) ...

31
adattare interfacce diverse Proxy, Adaptor e
Decorator
  • Molto spesso librerie diverse espongono
    interfacce diverse per fare la stessa cosa
  • Windows e MacOS sono ambienti grafici
    incompatibili tra loro
  • Una stessa soluzione si adatta a svariati
    problemi
  • si scrivono nuove classi che impongano una stessa
    interfaccia e uno stesso insieme di precondizioni
    e postcondizioni
  • Gli esemplari delle nuove classi usano un oggetto
    interno che contiene la vera implementazione
  • esempio del motto Every problem in computer
    science can be solved by adding another level of
    indirection
  • loggetto visibile all esterno si chiama oggetto
    esterno

32
Adaptor
  • La strategia delineata nella slide precedente
    prende il nome di Adaptor quando linterfaccia
    delloggetto interno è diversa da quella
    delloggetto esterno
  • Loggetto esterno e lAdapter, quello interno
    lAdaptee.
  • le librerie di classi per linterfaccia grafica,
    come AWT o Swing, non sono altro che enormi
    raccolte di oggetti Adapter
  • in Java, java.io.OutputStreamWriter permette di
    scrivere caratteri a 16-bit (Unicode) su di un
    OutputStream che lavora per byte
  • gli skeleton di RMI mappano su di un protocollo
    binario i metodi di uninterfaccia Java

33
UML
34
Proxy
  • Quando loggetto interposto espone esattamente la
    stessa interfaccia delloggetto separato, di cui
    fa le veci, esso prende il nome di Proxy
  • java.util.zip.DeflaterOutputStream comprime
    automaticamente i dati scritti
  • Scopo del Proxyposporre o addirittura evitare
    listanziazione di oggetti pesanti, se non
    necessaria
  • es. gli stub di RMI sembrano oggetti locali, ma
    si occupano di serializzare i parametri, inviarli
    in rete, attendere il risultato, ecc., senza però
    essere i veri oggetti

35
UML
36
Documentazione UML del pattern Proxy
Client
Proxy
Server
1 request( )
2 preProcess( )
3
4 request( )
5
6 postProcess( )
Some private processing
operations
7
37
Decorator
  • Altre volte, invece, loggetto fornisce
    funzionalità aggiuntive prende allora il nome di
    Decorator
  • java.util.zip.CheckedOutputStream calcola un
    checksum al volo e possiede un metodo aggiuntivo
    per restituirlo
  • La libreria di classi di Java (Stream, RMI,
    interfaccia grafica) utilizza pesantemente
    Adaptor, Proxy e Decorator

38
Conclusione
  • I pattern forniscono un vocabolario comune tra i
    progettisti, che facilita la comprensione di un
    progetto esistente o lo sviluppo di uno nuovo
  • Abbiamo visto solo un piccolo insieme di pattern
  • Factory, Singleton, Flyweight, State, Strategy,
    Proxy, Adaptor, Decorator
  • I pattern migliorano le prestazioni del codice
    e/o lo rendono più flessibile
  • Tuttavia, il codice che utilizza i pattern
    potrebbe risultare più complesso del necessario
    occorre quindi valutare e confrontare costi e
    benefici
  • Svantaggio potenziale pattern possono rendere la
    struttura del codice piucomplessa del
    necessario di volta in volta bisogna decidere se
    adottare semplici soluzioni ad hoc o riutilizzare
    pattern noti
  • pericolo di overdesign ricordare i seguenti
    motti
  • when in doubt, leave it out
  • keep it simple

39
Esercizio collezione di elementi con somma
  • Si implementi il tipo collezione di elementi con
    somma (SumSet). Man mano che nuovi elementi
    vengono aggiunti o tolti dalla collezione viene
    aggiornata la somma degli elementi
  • Quindi deve esistere l'operazione di somma per
    gli elementi da inserire
  • Si utilizzi il pattern Strategy, utilizzando un
    interfaccia Adder che definisce un metodo per la
    somma

40
Interfaccia Adder
  • public interface Adder //OVERVIEW
  • public Object add(Object x, Object y)
  • throws ClassCastException, NullPointerException
  • public Object sub(Object x, Object y)
  • throws ClassCastException, NullPointerException
  • public Object zero()
  • NB interfaccia Adder non è supertipo dei tipi i
    cui elementi vanno sommati
  • Serve, per ogni dato tipo che si voglia inserire
    nellinsieme a (definire classi per) creare
    oggetti con metodi per sommare o sottrarre
    elementi di quel tipo
  • NB si paga il prezzo della maggiore flessibilità
    con una maggior quantità di definizioni (un nuovo
    tipo aggiuntivo per ogni tipo di oggetto da
    inserire
  • Obiettivo (non perdiamolo di vista!) ottenere
    classe SumSet polimorfa che non deve essere
    modificata per inserire nuovi tipi di oggetti

41
Unimplementazione di Adder PolyAdder
  • public class PolyAdder implements Adder
  • private Poly z // il Poly zero
  • public PolyAdder() z new Poly()
  • public Object add (Object x, Object y)
  • throws NullPointerException,
    ClassCastException
  • if ( x null y null) throw new
    NullP.
  • return ((Poly) x).add((Poly) y)
  • public Object sub (Object x, Object y)
  • // simile ad add
  • public Object zero () return z
  • NB I metodi di PolyAdder (add e sub) sono
    distinti e diversi dai metodi omonimi di Poly
    signature diversa. Per inserire oggetti Integer
    in SumSet occorrerebbe definire IntegerAdder
    con add e sub, che Integer non possiede.

42
Classe SumSet (con implementazione parziale)
  • public class SumSet //OVERVIEW
  • private Vector els // contiene gli elementi
  • private Object sum // contiene la somma
  • private Adder a //oggetto per sommare e
    sottrarrre
  • public SumSet (Adder p) throws NullPointerExceptio
    n
  • els new Vector() a p sum p.zero()
  • public void insert (Object x) throws NullP,
    ClassCastEx
  • sum a.add(sum, x)
  • public Object getSum()return sum

43
Classe SumSet (cont.)
  • Ogni oggetto SumSet definito in termini
    (corredato) di qualche oggetto Adder
  • Elementi di SumSet tutti omogenei
  • ma ora tipo degli elementi determinato alla
    creazione della collezione dalloggetto Adder
    passato al costruttore non puo cambiare
  • Adder a new PolyAdder()
  • SumSet s new SumSet(a)
  • s.insert(new Poly(3, 7))
  • s.insert(new Poly(4, 8))
  • Poly p (Poly) s.sum() // p e 3x74x8
  • NB loggetto SumSet s può contenere solo oggetti
    Poly, perché costruito con un PolyAdder. Verifica
    però fatta a run-time...
Write a Comment
User Comments (0)
About PowerShow.com