Design pattern
Strutturali 1
Alfredo Milani
Dipartimento di Matematica e Informatica
Università degli Studi di Perugia
Sommario
Pattern di progetto
Cosa sono
Perché studiarli
Classificazione
Catalogo dei pattern
Classificazioni dei pattern
I pattern strutturali
2
Bibliografia
[GoF] E. Gamma, R. Helm, R. Johnson, J. Vlissides (GoF,
Gang of Four), Design Patterns – Elements of
Reusable Object-Oriented Software, Addison Wesley,
1994 (anche in Italiano)
[ST] A. Shalloway & J. R. Trott, Design Patterns
Explained, Addison Wesley, 2002
[M] S. J. Metsker, Design Patterns Java Workbook,
Addison wesley, 2002 (anche in italiano)
[C] J. Cooper, The design patterns Java Companion,
http://www.patterndepot.com/put/8/JavaPatterns.htm
[E] B. Eckel, Thinking in Patterns, www.mindview.net,
2003
3
Perché studiare i pattern?
Didatticamente:
Esempi di buon software OO
Pattern : Programmazione OO =
Strutture controllo : Programmazione strutturata
“I pattern sono l’equivalente della
programmazione strutturata nel caso OO”
Professionalmente
Utili per pensare a un livello più alto
Vocabolario, terminologia
4
Tre categorie
Strutturali
Strutture tipiche
Comportamentali
Gestione di comportamenti
Creazionali
Come creare oggetti in modo controllato
Discusse, esistono alternative
5
Classificazione dei pattern
Strutturali Creazionali Comportamentali
1. Adapter 8. Factory 13. Template Method
(Adattatore) Method (Metodo sagoma)
2. Façade (Metodo 14. Strategy (Strategia)
(Facciata) fabbrica) 15. State (Stato)
3. Composite 9. Abstract
16. Command (Comando)
(Composto) Factory
(Fabbrica 17. Observer (Osservatore)
4. Decorator 18. Mediator (Mediatore)
(Decoratore) astratta)
10. Singleton 19. Memento (Memento,
5. Bridge Ricordo)
(Ponte) (Singoletto)
11. Prototype 20. Iterator (Iteratore)
6. Proxy
(Proxy) (Prototipo) 21. Visitor (Visitatore)
12. Builder 22. Chain of Responsibility
7. Flyweight
(Peso piuma) (Costruttore) (Catena di responsabilità)
© A. Milani - Design 23. Interpreter (Interprete) 6
pattern
1. Adapter (Adattatore)
Scopo (Intent): Adattare l’interfaccia di una
classe già pronta all’interfaccia che il cliente
si aspetta
(“Adapter” da “riduttore” per prese di
corrente)
7
Scopo
Dati:
Un cliente che si aspetta
una classe/oggetto che fornisce certi servizi
con una certa interfaccia (nome di classe, metodi e
loro segnature)
Una classe che
fornirebbe quei servizi
ma ha un’interfaccia diversa da quella attesa
Adapter adatta l’interfaccia diversa a quella
attesa
8
Esempio (1/3)
Figura
Gerarchia…
+ set Posiz ione()
+ get Posiz ione()
+ display()
+ riem pi()
+ set Colore()
Punto Linea Quadrato
+ display() + display() + display()
+ riem pi() + riempi() + riempi()
9
Esempio (2/3)
Vogliamo aggiungere Cerchio
Lo implementiamo da zero? Circle
Fatica inutile…
Usiamo la classe Circle? + di splayIt()
+ fill(c : Color)
Ha un’interfaccia diversa… + set Center()
Creiamo un adattatore
(Nota: non possiamo modificare Circle…)
Non abbiamo il sorgente
È usato così com’è
…
10
Esempio (3/3)
Figura
- colore : Color
+ setPosizione()
+ getPosizione()
+ display()
+ riempi()
+ setColore()
Punto Linea Quadrato Ce rchi o -ci rcl e
+ display() + display() + display() + di splay()
Circle
+ riempi() + riempi() + riempi() + riem pi()
+ displayIt()
+ fill(c : Color)
display -> circle.displayIt() + setCenter()
riempi() -> circle.fill(colore)
11
Considerazioni
Circle non potrebbe essere una sottoclasse
di Figura
Cerchio deve avere una certa interfaccia (in
questo caso “imposta” dall’ereditarietà da
Figura)
Cerchio adatta Circle all’interfaccia
attesa
12
Due tipi di Adapter
Oggetto adattatore (Object Adapter)
Basato su delega/composizione
Classe adattatore (Class Adapter)
Basato su ereditarietà
L’adattatore eredita sia dall’interfaccia attesa sia
dalla classe adattata
No eredità multipla ⇒ l’interfaccia attesa deve
essere un’interfaccia, non una classe
(Due pattern?)
13
Diagramma Class Adapter
<<Interface>> Adatt ato
Cliente
Obiettivo
+ m'()
+ m()
Obiettivo x; ClassAdapter
...
x.m(); m -> thi s.m '();
+ m()
14
Diagramma Object Adapter
Cliente Obiettivo Adattato
+ m() + m'()
ObjectAdapter
Obiettivo x;
... -adattato
x.m(); + m()
m -> adattato.m'()
Nota: Object Adapter non eredita…
15
Adapter: riassunto e commenti
Si usa quando si vuole riusare una classe esistente,
magari progettata per il riuso, ma con interfaccia
“sbagliata” (diversa)
Quindi, d’ora in poi, possiamo fregarcene se una
classe ha un’interfaccia “sbagliata”: ci mettiamo un
Adapter e via!
Adapter potrebbe anche modificare leggermente il
comportamento di Adattato (ma modifiche
“pesanti” → altri pattern)
Un object adapter può adattare più classi…
16
2. Façade (facciata)
Scopo
Rendere più semplice l’uso di un sistema
Fornire un’unica interfaccia per un insieme di
funzionalità “sparse” su più interfacce/classi
17
Esempi
Classi per disegno 3D per disegnare in 2D
Compilatore
Classi Parser, Scanner, Token,
SyntacticTree, CodeGenerator, ecc.… vs.
Classe Compiler con metodo compile()
Manuale di installazione rapida della
stampante
Di solito funziona
Se non va c’è sempre il manuale dettagliato…
18
Diagramma Façade
sottosistema
C1
Cl ie nt Facade
C4
C2
C5 C6
C3
19
Vantaggi Façade
Promuove un accoppiamento debole fra
cliente e sottosistema
Nasconde al cliente le componenti del
sottosistema
Il cliente può comunque, se necessario,
usare direttamente le classi del sottosistema
20
Commenti
È un pattern facile
Spesso ha solo metodi statici
Façade, utilità e demo
Façade
Utilità (utility) in UML
Classe con solo metodi statici
Demo
Classe che mostra come usare una classe o un
(sotto)sistema
Di solito è un’applicazione (giocattolo) autonoma
21
Façade vs. Adapter
Entrambi sono “wrapper” (involucri)
Entrambi si basano su un’interfaccia, ma:
Façade la semplifica
Adapter la converte
22
3. Composite (Composto)
Scopo
Comporre oggetti in strutture ricorsive ad albero
per rappresentare gerarchie parte-tutto
e consentire ai clienti di trattare in modo
uniforme oggetti singoli/semplici e composizioni
di oggetti
È un bel pattern
23
Esempio (1/5)
Programma di grafica
Deve consentire di
Creare oggetti semplici (Punto, Linea, Cerchio,…)
Raggruppare dinamicamente oggetti semplici in
oggetti composti (4 linee in un rettangolo, …)
Trattare gli oggetti composti come se fossero
oggetti semplici
24
Esempio (2/5)
Raggruppare quattro linee per fare un
rettangolo
Raggruppare N linee per fare una
serpentina
Raggruppare un rettangolo e una
serpentina…
…
…Proviamo a fare un diagramma
UML…
25
Esempio (3/5)
1o tentativo: cos’è che non va?
Gruppo
Figura 0.. *
+ add( : Figura)
-componenti + remove( : Figura)
+ draw() + draw()
for (...) {
Punto Linea Cerchi o
componenti.draw();
}
+ draw() + draw() + draw()
Risp.: gestione Gruppo ≠ gestione Figura…
26
Esempio (4/5)
2o tentativo: Gruppo sottoclasse di Figura!
Questa è l’idea base del Composite
Figura 0..*
+ draw()
Punto Linea Cerchi o Gruppo
+ draw() + draw() + draw() + add( : Figura)
+ remove( : Figura) -componenti
+ draw()
for (...) {
componenti.draw();
}
27
Esempio (5/5)
Un punto/cerchio/linea è una figura…
…“Trattare gli oggetti composti come se
fossero oggetti semplici”…
Un gruppo è una figura!
La ricorsione è in:
Gruppo contiene Figura,
e siccome alcune figure sono gruppi (Gruppo
sottoclasse di Figura)
un gruppo contiene gruppi…
28
Diagramma oggetti: albero!
Per rappresentare il gruppo
rettangolo+serpentina+linea:
3 istanze di Gruppo
14 istanze di Linea
:Gruppo Linea
Serpent ina
Rettangolo
:Gruppo
l0: Lin ea :Gruppo
l1:Linea l2: Linea l3:Linea l4: Lin ea l5: Linea … l13:Linea
29
Diagramma Composite
Component
Cl ient
+ operation()
+ add() n
+ remove()
+ getChildren()
Leaf Composite
+ operation() + operation()
+ add() -children
+ remove()
+ getChilldren()
30
Commenti
Semplifica il cliente, che tratta strutture
composte e singoli oggetti in modo uniforme
In tutti i punti in cui il cliente si aspetta un
oggetto primitivo, gli si può passare un oggetto
composto
Interfaccia di Component
Massimizzazione → flessibilità: il Client non
distingue oggetti atomici e composti. Però, che
implementazione per add su una foglia?
Minimizzazione → sicurezza: no problem per add
sulle foglie, però interfacce diverse…
31
Commenti
Leaf e Composite possono:
essere astratte
avere sottoclassi (ed è facile aggiungerne…)
Cicli (contenimento di se stesso, mutuo
contenimento) possono causare ricorsione ∞
nelle visite
Memorizzare i nodi visitati…
Usato in java.awt: Component e
Container
Può rendere il progetto troppo generico
32
4. Decorator (Decoratore)
Scopo
Aggiungere dinamicamente a un oggetto
responsabilità/funzionalità/operazioni
Alternativa (più flessibile) alla creazione di
sottoclassi per l’estensione di funzionalità
(anche la specializzazione può aggiungere
responsabilità/funzionalità/operazioni)
33
Esempio
Come ottenerlo?
34
Aggiungere responsabilità
AreaDiTesto
staticamente?
AreaDiTesto AreaDiTestoC onB ar
Ereditarietà ConBordo raScorrimento
Creo istanze della classe voluta
Contro
AreaDiTestoConBordoEBarraScorrimento?
AreaDiTestoConBarraScorrimentoEBordo?
Altre 2 sottoclassi?
Statico: non posso aggiungere funzionalità dopo la
creazione
Altre componenti? (Finestra) Duplicazione!
35
Aggiungere responsabilità
dinamicamente
Racchiudere l’oggetto da “decorare” (l’area di
testo) in un altro oggetto, responsabile di
gestire la “decorazione” (il bordo, la
scrollbar): il “decoratore”
Il decoratore trasferisce/delega e fa qualcosa
in più (prima o dopo)
Il decoratore ha l’interfaccia conforme
all’oggetto decorato, e quindi è trasparente al
cliente
36
Di nuovo l’esempio
Componente 1
Grafi co
+ draw()
AreaDiTesto Decoratore -decorato
+ draw() + draw()
draw() ->
decorato.draw()
DecoratoreBordo DecoratoreBarra
- spessoreBordo Scorrimento
- posizioneScroll
+ draw()
draw() -> + drawBorder() + draw()
super. draw(); + scrollTo() draw() ->
drawBorder(); s crol lTo();
s uper. draw();
37
Diagramma degli oggetti
Catena con
Varie decorazioni
Alla fine, un’istanza di AreaDiTesto
new DecoratoreBordo(
new DecoratoreBarraScorrimento(
new AreaDiTesto()))
new DecoratoreBarraScorrimento(
new DecoratoreBordo(
new AreaDiTesto()))
z:Decoratore
Bordo -decorato
y:DecoratoreBarra
Scorrimento -decorato
x:AreaDiTesto
38
Diagramma Decorator
Cliente Componente
+ operazione() 1
Compo nente Concret o Decoratore -decorato
+ operazione() + operazione()
operazione ->
deco rato.op erazione()
Decoratore2 Decoratore1
- statoAggiunto
+ operazione()
+ com portam entoAgg iunti vo() + operazione()
operazione ->
super.ope razi one();
comport amentoAggiunt o();
39
Decoratore vs. ereditarietà
Dinamico (run time) Statico (compile time)
Senza vincoli per il Con vincoli per il
client (può client (non può
inventarsi combinazioni inventarsi combinazioni
non previste) non previste)
Aggiunge responsabilità Aggiunge responsabilità
a un singolo oggetto a (tutte le istanze di)
una classe
Evita esplosione Può causare esplosione
combinatoria combinatoria
40
Usi tipici del Decorator
Stream Java
Interfacce utente grafiche
Componente grafica
area di testo, finestra, panel, …
decorata con
bordo, barra di scorrimento, …
(eventualmente più di uno!)
Non usata nelle Swing di Java
JComponent ha setBorder
41
Decorator vs. Composite
Un Decoratore può essere visto come un
Composite degenere con un singolo
componente
(cfr. la molteplicità e il diagramma degli oggetti)
Però:
Un Composite ha lo scopo di aggregare oggetti
Un Decoratore ha lo scopo di aggiungere
responsabilità/funzionalità a un oggetto
Spesso usati insieme (?)
42
Decorator vs. Adapter
Decorator
Arricchisce di funzionalità senza modificare
l’interfaccia
modifica le responsabilità di un oggetto, non la
sua interfaccia
Adapter modifica l’interfaccia di un oggetto
(può anche arricchire, aggiungere
responsabilità/funzionalità, ma in modo limitato)
43