• Non ci sono risultati.

Design Pattern GoF Pattern Strutturali

N/A
N/A
Protected

Academic year: 2022

Condividi "Design Pattern GoF Pattern Strutturali"

Copied!
43
0
0

Testo completo

(1)

Ingegneria del Software

Design Pattern GoF

Pattern Strutturali

Prof. Orazio Tomarchio

Classificazione Design Patterns

(2)

O. Tomarchio Ingegneria del Software 3

1. Adapter (Adattatore)

Scopo:

Adattare l’interfaccia di una classe già pronta all’interfaccia che il cliente si aspetta

(“Adapter” da “riduttore” per prese di corrente)

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

(3)

O. Tomarchio Ingegneria del Software 5

Esempio (1/3)

Solita gerarchia… Figura

+ setPosizione() + getPosizione() + display()

+ riempi() + setColore()

Punto + display() + riempi()

Linea + display() + riempi()

Quadrato + display() + riempi()

Esempio (2/3)

Vogliamo aggiungere Cerchio

Lo implementiamo da zero?

Fatica inutile…

Usiamo la classe Circle?

Ha un’interfaccia diversa…

Creiamo un adattatore

(Nota: non possiamo modificare Circle…)

Non abbiamo il sorgente

È usato così com’è

Circle

+ displayIt() + fill(c : Color) + setCenter()

(4)

O. Tomarchio Ingegneria del Software 7

Esempio (3/3)

Figura - colore : Color + setPosizione() + getPosizione() + display()

+ riempi() + setColore()

Punto + display() + riempi()

Linea + display() + riempi()

Quadrato + display() + riempi()

Cerchio + display()

+ riempi() Circle

+ displayIt() + fill(c : Color) + setCenter() display -> circle.displayIt()

riempi() -> circle.fill(colore)

-circle

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 attesaadatta

(5)

O. Tomarchio Ingegneria del Software 9

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?)

Diagramma Class Adapter

Cliente Obiettivo

+ m()

<<Interface>>

ClassAdapter + m()

Obiettivo x;

...

x.m(); m -> this.m'();

Adattato + m'()

(6)

O. Tomarchio Ingegneria del Software 11

Diagramma Object Adapter

Nota: Object Adapter non eredita…

Cliente

Obiettivo x;

...

x.m();

ObjectAdapter + m()

Adattato + m'()

m -> adattato.m'() -adattato

Obiettivo + m()

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…

(7)

O. Tomarchio Ingegneria del Software 13

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

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…

(8)

O. Tomarchio Ingegneria del Software 15

Diagramma Façade

C5 C6

C1

C4 C2

Facade

C3 Client

sottosistema

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

(9)

O. Tomarchio Ingegneria del Software 17

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

Façade vs. Adapter

Entrambi sono “wrapper” (involucri)

Entrambi si basano su un’interfaccia, ma:

Façade la semplifica

Adapter la converte

(10)

O. Tomarchio Ingegneria del Software 19

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

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 sempliciTrattare gli oggetti composti come se fossero oggetti semplici

(11)

O. Tomarchio Ingegneria del Software 21

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…

Esempio (3/5)

1o tentativo: cos’è che non va?

Punto + draw()

Linea + draw()

Cerchio + draw()

Gruppo

+ add( : Figura) + remove( : Figura) + draw()

Figura + draw()

0..*

for (...) {

componenti.draw();

} -componenti 0..*

Risp.: gestione Gruppo  gestione Figura…

(12)

O. Tomarchio Ingegneria del Software 23

Esempio (4/5)

2o tentativo: Gruppo sottoclasse di Figura!

Questa è l’idea base del Composite

Punto + draw()

Linea + draw()

Cerchio + draw() Figura

+ draw()

Gruppo + add( : Figura) + remove( : Figura) + draw()

0..*

0..*

-componenti for (...) {

componenti.draw();

}

Esempio (5/5)

Un punto/cerchio/linea è una figura…

…“Trattare gli oggetti composti come se fossero oggetti semplici”…

Un gruppo è unaè una figura!

La ricorsione è in:

Gruppo contiene Figura,

e siccome alcune figure sono gruppi (Gruppo sottoclasse di Figura)

un gruppo contiene gruppi…

(13)

O. Tomarchio Ingegneria del Software 25

Diagramma oggetti: albero!

Per rappresentare il gruppo rettangolo+serpentina+linea:

3 istanze di Gruppo

14 istanze di Linea

l1:Linea l2:Linea l3:Linea l4:Linea :Gruppo

l5:Linea l13:Linea

:Gruppo

Serpentina Rettangolo

:Gruppo

l0:Linea

Linea

Diagramma Composite

Leaf + operation()

Component

+ operation() + add() + remove() + getChildren()

Composite + operation() + add() + remove() + getChilldren()

n

-children Client

n

(14)

O. Tomarchio Ingegneria del Software 27

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…

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

(15)

O. Tomarchio Ingegneria del Software 29

Commenti: non solo grafica

Rappresentare espressioni con alberi sintattici

E ::= EC | V

EC ::= ‘(’E ‘+’ E‘)’

V ::= ‘a’ | ‘b’ | ‘c’ |…| ‘z’

((a + b) + (c + d))

Usato in JUnit, vedremo

V

EA EC

E

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)

(16)

O. Tomarchio Ingegneria del Software 31

Esempio

Come ottenerlo?

Aggiungere responsabilità staticamente?

Ereditarietà

Creo istanze della classe voluta

Contro

AreaDiTestoConBordoEBarraScorrimento?

AreaDiTestoConBarraScorrimentoEBordo? Altre 2 sottoclassi?

AreaDiTesto

AreaDiTesto ConBordo

AreaDiTestoConBar raScorrimento

(17)

O. Tomarchio Ingegneria del Software 33

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

Di nuovo l’esempio

AreaDiTesto + draw()

DecoratoreBordo - spessoreBordo + draw()

+ drawBorder()

DecoratoreBarra Scorrimento - posizioneScroll + draw()

+ scrollTo() Decoratore

+ draw() Componente

Grafico + draw()

11

-decorato

draw() ->

decorato.draw()

draw() ->

draw() ->

super.draw();

(18)

O. Tomarchio Ingegneria del Software 35

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

y:DecoratoreBarra Scorrimento

x:AreaDiTesto -decorato

-decorato

Diagramma Decorator

ComponenteConcreto + operazione()

Decoratore2 + operazione()

Decoratore + operazione() Componente

+ operazione() 1

Decoratore1 - statoAggiunto

-decorato 1

Cliente

operazione ->

decorato.operazione()

(19)

O. Tomarchio Ingegneria del Software 37

Decoratore vs. ereditarietà

Dinamico (run time)

Senza vincoli per il cliente (può inventarsi

combinazioni non previste)

Aggiunge responsabilità a un singolo oggetto

Evita esplosione combinatoria

Statico (compile time)

Con vincoli per il

cliente (non può inventarsi combinazioni non previste)

Aggiunge responsabilità a (tutte le istanze di) una classe

Può causare esplosione combinatoria

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

(20)

O. Tomarchio Ingegneria del Software 39

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 (?)

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)

(21)

O. Tomarchio Ingegneria del Software 46

Esercizio

Chiosco “Etneo”

Vende “cibarie”

Pizze, calzoni, toast, tramezzini, piadine, panini, focacce, …

Con ingredienti a scelta fra:

Prosciutto, formaggio, mozzarella, funghi, spinaci, speck, gorgonzola, nutella, marmellata, …

Eventualmente “doppi” o “tripli” o …

Non modellate tutta la gestione, solo le classi che consentano la creazione di cibarie

Esercizio 1

Tutte le combinazioni, una classe per ognuna

PizzaAlProsciutto, PiadinaNutella,

PizzaMozzarellaERucola, PizzaNutellaEAsparagi, …

Eventualmente usiamo l’ereditarietà

Problemi:

Argh! Con N cibi e M ingredienti ci sono N*M combinazioni. Servono proprio tutte ste classi?

Eliminiamo PizzaNutellaEAsparagi e simili? E se arriva Toni che vuole proprio quella/e?

(22)

O. Tomarchio Ingegneria del Software 48

Esercizio 2

Pizza Calzone Toast Tramezzino Piadina Panino Focaccia

Cibaria

Prosciutto Mozzarella Funghi Formaggio Spinaci Nutella Marmellata Ingredienti

Come li combiniamo?

Esercizio 3

Così?

Pizza Calzone Toast Tramezzino Piadina Panino Focaccia

Cibaria

Ingredienti

0..n

-ingredienti

0..n

(23)

O. Tomarchio Ingegneria del Software 50

Esercizio 4

… …

Pizza Focaccia ConProsciutto ConMarmellata CibariaDiBase

Cibaria

Ingredienti 11

Cliente

Cibaria c1 =

new ConMarmellata(

new ConProsciutto(

new ConProsciutto(

new Pizza());

Cibaria c2 = new Pizza());

Cibaria c3 =

new ConMarmellata(

new ConAsparagi(

new ConProsciutto(

new Focaccia());

Esercizio 5

È un Decoratore?

Che responsabilità/funzionalità aggiungo?

È un Composite?

Però aggiungo un solo ingrediente alla volta, non raggruppo…

Uhm, un po’ Decoratore senza aggiunta di funzionalità, un po’ Composite “degenere”…

(24)

O. Tomarchio Ingegneria del Software 52

5. Bridge (Ponte)

Scopo

Separare un’astrazione dalla sua implementazione

per far sì che possano variare indipendentemente

EH?!

Bel pattern, ma difficile (si capisce subito)

Spiegato male sul GoF…

Ricaviamolo, lavorando su un esempio

Esempio

Dobbiamo scrivere un programma che disegna rettangoli

usando, in alternativa, uno di due programmi di disegno

PD1: drawALine(x1, y1, x2, y2)

PD2: drawLine(x1, x2, y1, y2)

So quale dei due programmi usare al momento dell’istanziazione dei rettangoli

Il cliente non deve preoccuparsene

(25)

O. Tomarchio Ingegneria del Software 54

Prima soluzione (ingenua…)

2 tipi di rettangoli, uno usa PD1 e l’altro PD2

All’istanziazione so se istanziare

Rettangolo1 o Rettangolo2

Cliente

Rettangolo

+ draw()

# drawLine()

Rettangolo1

# drawLine()

PD1 + drawALine()

Rettangolo2

# drawLine()

PD2 + drawLine()

<<calls>>

<<calls>>

Prima soluzione (ingenua…)

2 tipi di rettangoli, uno usa PD1 e l’altro PD2

All’istanziazione so se istanziare

Rettangolo1 o Rettangolo2

Cliente

Rettangolo

+ draw()

# drawLine()

Rettangolo1

# drawLine()

PD1

Rettangolo2

# drawLine()

PD2

<<calls>>

<<calls>>

(26)

O. Tomarchio Ingegneria del Software 56

Mi ero dimenticato…

… che voglio disegnare anche cerchi,

Per fortuna PD1 e PD2 hanno

PD1: drawACircle(x, y, r)

PD2: drawCircle(x, y, r)

e sempre consentendo al cliente di astrarre

Cerchi come rettangoli  Figura

Seconda soluzione…

… revisione della prima

Cliente

Rettangolo + draw()

# drawLine()

Rettangolo1

# drawLine()

Rettangolo2

# drawLine() Figura + draw()

Cerchio + draw()

# drawCircle()

Cerchio1

# drawCircle()

Cerchio2

# drawCircle() draw ->

drawLine()

draw ->

drawCircle()

(27)

O. Tomarchio Ingegneria del Software 58

Seconda soluzione…

… revisione della prima

Cliente

Rettangolo + draw()

# drawLine()

Rettangolo1

# drawLine()

Rettangolo2

# drawLine() Figura + draw()

Cerchio + draw()

# drawCircle()

Cerchio1

# drawCircle()

PD1 + drawALine() + drawACircle()

<<calls>>

Cerchio2

# drawCircle()

PD2 + drawLine() + drawCircle()

<<calls>> <<calls>>

<<calls>>

draw ->

drawLine()

draw ->

drawCircle()

Come funziona

Codice del Cliente:

Vediamo le istanze

Vediamo il diagramma di sequenza

Figura[] f = new Figura[4];

f[0] = new Rettangolo1(...);

f[1] = new Rettangolo2(...);

f[2] = new Cerchio1(...);

f[3] = new Cerchio2(...);

for (i = ...) f[i].draw();

(28)

O. Tomarchio Ingegneria del Software 60 Cliente

Rettangolo

+ draw()

# drawLine()

Rettangolo1

# drawLine()

Rettangolo2

# drawLine() Figura + draw()

Cerchio

+ draw()

# drawCircle()

Cerchio1

# drawCircle()

PD1

+ drawALine() + drawACircle()

Cerchio2

# drawCircle()

PD2

+ drawLine() + drawCircle() draw ->

drawLine()

draw ->

drawCircle()

<<calls>> <<calls>> <<calls>> <<calls>>

:Cliente f[0]:Rettangolo1 [Figura] :PD1

new()

getReference()

draw()

drawLine()

drawALine() drawLine() drawALine()

drawLine() drawALine()

(29)

O. Tomarchio Ingegneria del Software 62

Commenti

E se devo gestire altre figure?

Per ogni ulteriore figura aggiungo una piccola gerarchia (3 classi)

Classe astratta

Una sottoclasse per ogni PD

E se per caso devo gestire/usare anche altri programmi di disegno (PD3, PD4, …)?

Per ogni ulteriore PD aggiungo una classe PDi e una classe in ogni gerarchia

Sembra funzionare… ma non ci piace molto… Con N figure e M PD ho N*M classi a “livello 3”

Alternativa

Cliente Figura

+ draw()

Rettangolo1 + draw()

PD1 + drawALine() + drawACircle() Cerchio1

+ draw()

Rettangolo2 + draw() PD2

+ drawLine() + drawCircle()

Cerchio2 + draw() drawLine ->

pd1.drawALine() drawCircle ->

pd1.drawACircle()

Figura1

# drawLine()

# drawCircle()

<<calls>>

Figura2

# drawLine()

# drawCircle()

<<calls>>

(30)

O. Tomarchio Ingegneria del Software 64

Commenti

Ho scambiato “l’ordine”:

Da: Prima tipo di figura poi versione di PD

A: Prima versione poi tipo di figura

Mah, non è cambiato molto

Sempre N * M…

Uhm…

Scopo del Bridge

Separare un’astrazione dalla sua implementazione

per far sì che possano variare indipendentemente

Adesso capiamo! (?)

Astrazione: le figure

Implementazione: i programmi di disegno

Con la nostra soluzione

Alto accoppiamento fra figure (astrazione) e PD (implementazioni)

(31)

O. Tomarchio Ingegneria del Software 66

È di qualità?

Insomma, non ci piace

Separiamo astrazione e implementazioni

Astrazione: Figura

Ci sono 2 tipi di Figura

Implementazioni: Programmi di disegno (PD)

Anche qui ne abbiamo 2 versioni

Separiamo astrazione e implementazione

Astrazione

Implementazioni

Figura + draw()

Rettangolo

+ draw()

# drawLine()

Cerchio

+ draw()

# drawCircle()

PD

+ drawLine() + drawCircle()

PDVersione1

+ drawLine() + drawCircle()

PDVersione2 + drawLine() + drawCircle()

(32)

O. Tomarchio Ingegneria del Software 68

Come li colleghiamo?

Con un ponteponte (“bridge”)…

Una Figura delega la responsabilità del disegno (draw) a un (PD)

Già che ci siamo, un dettaglio:

Rifattorizziamo #drawLine e #drawCircle nella sopraclasse per evitare duplicazioni…

Sono protected 

Ereditati

Non visibili nell’interfaccia di Figura

Astrazione

Ponte

Diagramma finale

Rettangolo + draw()

Cerchio + draw()

PDVersione1

+ drawLine() + drawCircle()

PD1

PDVersione2

+ drawLine() + drawCircle()

PD2

<<calls>> <<calls>>

Figura

+ draw()

# drawCircle()

# drawLine()

PD

+ drawLine() + drawCircle() Cliente

(33)

O. Tomarchio Ingegneria del Software 70

Come funziona

Codice del Cliente:

Vediamo le istanze

(Diagramma di sequenza:

Ex.)

Figura[] f = new Figura[4];

PD p1 = new PDVersione1();

PD p2 = new PDVersione2();

f[0] = new Rettangolo(p1);

f[1] = new Rettangolo(p2);

f[2] = new Cerchio(p1);

f[3] = new Cerchio(p2);

for (i = ...) f[i].draw();

Istanze

Rettangolo + draw()

Cerchio + draw()

PDVersione1

+ drawLine() + drawCircle()

PD1

+ drawALine() + drawACircle()

PDVersione2

+ drawLine() + drawCircle()

PD2

+ drawLine() + drawCircle()

<<calls>> <<calls>>

Figura

+ draw()

# drawCircle()

# drawLine()

PD

+ drawLine() + drawCircle() Cliente

(34)

O. Tomarchio Ingegneria del Software 72

Commenti

Abbiamo

eliminato un po’ di ereditarietà

aggiunto composizione/delega

Non c’è più esplosione combinatoria

N + M classi, non N * M

Come ci siamo arrivati?

Scopo del Bridge (finalmente chiaro…)

Separare un’astrazione dalla sua implementazione Separare

per far sì che possano variarevariare indipendentementeindipendentemente

Diagramma del Bridge

Cliente

Astrazione1 Astrazione2 Implementazione

Concreta1 Implementazione Concreta2 Astrazione

+ op()

Implementazione + opImpl()

-impl

op ->

impl.opImpl()

(35)

O. Tomarchio Ingegneria del Software 74

Commenti

Spesso interfaccia e implementazione

sono nella stessa classe,

o vengono separate in sopraclasse e sottoclasse

Bridge le separa “di più”

Evita anche ricompilazioni

Morale più generale:

Mai accontentarsi della prima versione…

… però evitare la “paralysis by analysis”…

Il Bridge secondo Eckel

Bridge è uno strumento per il programmatore:

gli permette di organizzarsi il codice

per poter aggiungere nuove astrazioni (front-end) e nuove implementazioni (back-end) in modo semplice

Si potrebbe usare delegazione invece di ereditarietà nella variazione di astrazioni

Pro

Astrazioni con interfacce diverse

Contro

Cliente non può usare il polimorfismo

(36)

O. Tomarchio Ingegneria del Software 76

Bridge vs. Adapter

Obiettivi diversi

Adapter adatta, Bridge separa interfaccia e implementazione per farle variare indipendentemente

Bridge si usa tipicamente all’inizio di un progettoinizio di un progetto,

Adapter viene usato dopo che le classi coinvolte sono state progettate/implementate e vengono riusateriusate

Comunque le classi PDVersione1 e PDVersione2 sono due adattatori oggetto…

Soluzione frequente

Bridge vs. Decoratore

Obiettivo in comune: evitare la proliferazione (esplosione combinatoria) di classi

Struttura diversa

(37)

O. Tomarchio Ingegneria del Software 78

6. Proxy

Scopo

Fornire un surrogato o un segnaposto per un oggetto

Per controllarne l’accesso

Esempi

Per efficienza: In un word processor, caricare le figure solo al bisogno evitando di caricarle tutte all’inizio

Per sicurezza: Segnaposto che controlla e gestisce i privilegi d’accesso

Segnaposto in word processor

WordProcessor Figure

- dim : Dimension + draw()

+ getDimension() + store()

+ load()

getDimension() ->

if (figure==null)

return figure.getDimension();

else

return dim;

ProxyFigure - fileName + draw()

+ getDimension() + store()

+ load()

RealFigure - ...implementation...

+ draw()

+ getDimension() + store()

+ load() -figure

(38)

O. Tomarchio Ingegneria del Software 80

Diagramma del Proxy

Client Subject

+ request()

Proxy + request()

RealSubject + request() -real

request ->

...

real.request();

...

Commento

Pattern facile

Altro tipo di “wrapper”

4 tipi di Proxy

Proxy remoto

Rappresentante locale per oggetto in spazio  (Es.: RMI, Remote Method Invocation)

Proxy virtuale

Gestisce la creazione su richiesta di oggetti “costosi” (Es.: immagine in word processor)

Proxy di protezione

Gestisce diritti di accesso  per oggetti 

Riferimento intelligente

Sostituisce un puntatore (Es.: #riferimenti per gestire la distruzione)

(39)

O. Tomarchio Ingegneria del Software 82

Copy-on-write

Uso tipico del Proxy

Copia di un oggetto grande/complicato

Costosa

E magari inutile, se non modifico…

Soluzione:

Non copio, metto un Proxy che controlla l’accesso

E copia solo quando l’oggetto viene modificato

7. Flyweight (Peso piuma)

Scopo

Usare la condivisione di oggetti/istanze

per rappresentare in modo efficiente un gran numero di oggetti

[a granularità fine (?)]

Migliorare le prestazioni (usare meno memoria)

“Performance hack” [Eckel]

Lo vediamo un po’ “di corsa”

(40)

O. Tomarchio Ingegneria del Software 84

L’idea

Cliente

X - x1 - x2- x2 - ...

- xn - xn

Tanti (10^6)

Pochi

… …

Cliente X'

- x1

Flyweight Flyweight - x2

- x2 - ...

- ...

- xn- xn -flyweight

Stati “interno” ed “esterno”

“Interno” (al flyweight)

Indipendenti dal contesto, condiviso

“Esterno”

Dipendenti dal contesto, individuale

Esempio

Caratteri in un word processor

Condiviso: rappresentazione font true type, funzioni per scalare, …

Individuale: dimensione, stile, posizione

(41)

O. Tomarchio Ingegneria del Software 86

Commenti

Più utile se tanti oggetti con duplicazione dati

Attenzione ai confronti con “==”!!

Flyweight vs. Decorator e Bridge

Decorator&Bridge: esplosione combinatoria classi

Flyweight: esplosione combinatoria oggetti

Spesso usato insieme al Composite per condividere le foglie

Factory per la creazione (ne parleremo)

Composite Component

Leaf

Flyweight

Riassunto

1. Adapter (Adattatore)

2. Façade (Facciata)

3. Composite (Composto)

4. Decorator (Decoratore)

5. Bridge (Ponte)

6. Proxy (Proxy)

7. Flyweight (Peso piuma)

(42)

O. Tomarchio Ingegneria del Software 88

Analisi dei pattern strutturali

Ci sono similitudini, ma sono 

Adapter e Bridge

Entrambi introducono un livello di indirezione e usano la delega,

Obiettivi e tempi , spesso usati insieme

Adapter e Façade

Façade come adattatore per tanti oggetti?

No, Façade definisce una nuova interfaccia, mentre Adapter usa interfacce preesistenti

Composite e Decorator

Composite  Decorator (diagrammi simili)

Complementari, spesso usati insieme

Dal punto di vista del pattern Decorator, un oggetto Composto è un ComponenteConcreto

Dal punto di vista del patter Composite, un oggetto Decoratore è una foglia (Leaf)

(43)

O. Tomarchio Ingegneria del Software 90

Decorator+Composite

ComponenteConcreto + operazione()

Decoratore2 + operazione()

+ comportamentoAggiuntivo() Decoratore + operazione()

Decoratore1 - statoAggiunto + operazione() Cliente

operazione ->

decorato.operazione()

operazione ->

super.operazione();

comportamentoAggiunto();

Composto + operazione()

Componente + operazione()

11

-decorato nn

-componenti

operazione ->

forall c in componenti (c.operazione())

Proxy e Decorator

Entrambi

Usano la composizione di un oggetto

Forniscono al cliente un’interfaccia = a quella dell’oggetto

Proxy (a differenza di Decorator):

non aggiunge/rimuove proprietà dinamicamente

è l’oggetto a decidere le funzionalità

(nel Decorator il decoratore aggiunge funzionalità!)

non consente composizione ricorsiva

la relazione fra proxy e oggetto è statica, compile time

Decorator gestisce aggiunta di funzionalità al run-time

Riferimenti

Documenti correlati

bool operator&lt;(const Integer&amp; left, const Integer&amp; right) { return left.i &lt;

Per costruire gli oggetti si deve seguire questo procedimento: 1) disegnare i pezzi sul legno, 2) tagliare i pezzi con il seghetto, 3) unirli con la colla (o in altro modo).

● Il problema e' risolto quando trovate il risultato in funzione dei soli dati (cioè solo di cose che conoscete).. ● Associate al vostro

[r]

 Si può anche usare il valore di ritorno come Si può anche usare il valore di ritorno come parametro nella chiamata di un altro metodo:. parametro nella chiamata di un

Dipartimento di Informatica Università “La Sapienza”.

public void draw(Window w, Position where){…}. public

La classe Impiegato eredita implicitamente i campi definiti dalla classe Persona.. Osservate che nella classe Impiegato non sono visibili le variabili