Corso di Laurea Specialistica in Ingegneria Informatica
Design Pattern
E. TINELLI
Corso di Ingegneria del Software
A. A. 2008 - 2009
Pattern e Design Pattern
• Soluzioni consolidate a problemi ricorrenti in contesti specifici
– Catturano soluzioni che sono già state adottare e che si sono evolute nel tempo
– Catturano le strutture statiche e dinamiche di soluzioni che ricorrono più volte
durante lo sviluppo di applicazioni in un particolare contesto
• Un pattern deve mostrare che la soluzione descritta è: Utile (ricorrenza);
Utilizzabile (contesto specifico); Usata (assodata)
• Goal dei Design Pattern
– Creare un linguaggio per comunicare intuizioni ed esperienza su problemi e
sulle loro soluzioni Æ Aiutare gli sviluppatori a risolvere problemi già trattati
– Offrire soluzioni generiche, riusabili, documentate e al tempo stesso
specifiche per una certa classi di problemi
“Ogni
“Ognipattern
patterndescrive
descriveun
unproblema
problemaspecifico
specificoche
chericorre
ricorrepiù
piùvolte
volte
nel
nelnostro
nostroambiente
ambienteeepoi
poidescrive
descriveililnucleo
nucleodella
dellasoluzione
soluzioneaa
quel
quelproblema,
problema,ininmodo
mododa
dapoter
poterutilizzare
utilizzaretale
talesoluzione
soluzione
un
unmilione
milionedidivolte,
volte,senza
senzamai
maifarlo
farloallo
allostesso
stessomodo”.
modo”.
C.
C. Alexander
Alexander et
et al.
al. AA Pattern
Pattern Language,
Language, 1977
1977
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
2
Ruolo dei Design Pattern
• Identificare gli oggetti necessari: scomporre sistema in oggetti è
compito difficile. Pattern aiutano nell’identificazione di oggetti che
rappresentano astrazioni non banali a partire dalla definizione del problema
che si vuole risolvere.
• Progettare anticipando i cambiamenti: Progettare il Sistema in modo da
anticipare i nuovi requisiti e i cambiamenti a quelli esistenti Æ Non esiste
una combinazione di Patterns che dia il massimo di flessibilità e di
facilità di evolvere.
• Controllare le dipendenze: Le dipendenze contenute in una
classe/interfaccia consistono nell’insieme dei riferimenti (statici) ad altre
classi/interfacce Æ I design pattern vengono classificati in base al tipo di
dipendenze su cui agiscono in: creazionali, strutturali,comportamentali
• Definizione delle interfacce: l’applicazione di un pattern porta con se le
scelte riguardanti le interfacce ed i meccanismi di interazione tra gli oggetti.
• Definire l’implementazione: applicare un pattern comporta specifiche
scelte implementative. In particolare vi sono pattern che si focalizzano su
ereditarietà mentre altri si focalizzano su meccanismi di composizione.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
3
Pattern – 4 elementi essenziali
• Nome - riferimento mnemonico che permette di aumentare il
vocabolario dei termini tecnici e ci permette di identificare il
problema e la soluzione in una o due parole
• Problema - descrizione del problema e del contesto a cui il
pattern intende fornire una soluzione. Potrebbe anche essere
descritto come una lista di condizioni necessarie per
l’applicazione del pattern
• Soluzione - descrive gli elementi fondamentali che costituiscono
la soluzione e le relazioni che intercorrono tra questi mediante
uno schema generale che può essere applicato in situazioni
diverse
• Conseguenze - specifica le possibili conseguenze che
l’applicazione della soluzione proposta può comportare. Si
riferiscono ad esempio a possibili di efficienza della soluzione,
oppure ad applicabilità con specifici linguaggi di programmazione
Æ utili per valutare soluzioni alternative
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
4
Pattern per la progettazione OO – principi e tecniche
• Ereditarietà di Interfaccia – l’ereditarietà di classi concrete permette
il riuso di codice mentre l’ereditarietà di classi puramente astratte
permette di definire oggetti con la stessa interfaccia Æ 1° Tecnica:
Programmare basandosi su un’interfaccia e non su
un’implementazione
• Esistono due possibilità per il riuso delle funzionalità (quindi di codice):
– white-box reuse (basato sull’ereditarietà)
• È semplice adattare le funzionalità di una classe antenata in una classe
derivata
• L’ereditarietà è definita in maniera statica, al compile-time
• Si viola parzialmente l’incapsulamento
– black-box reuse (basato sull’aggregazione/composizione)
• La composizione è definita dinamicamente, a run-time
• Gli oggetti contenuti devono avere interfacce ben definite e complete per
poter essere utilizzati correttamente
• Si preserva l’incapsulamento
Æ 2° Tecnica: Preferire l’aggregazione all’ereditarietà
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
5
Pattern Creazionali
• Astraggono il processo di istanziazione
– Nascondono i costruttori e introduco dei metodi al loro posto
– Tutto ciò che il sistema conosce sono le interfacce degli oggetti così come sono
state definite con opportune classi astratte
• Conseguenze:
– Incapsulano la conoscenza delle classi concrete usate
– Nascondono il modo in cui le istanze di queste classi vengono create e
assemblate
– Espongono interfacce al posto di tipi concreti
• Esempi
– Abstract Factory
– Factory Method
– Builder – separa la costruzione di un oggetto complesso dalla sua
rappresentazione in modo che lo stesso processo di costruzione possa essere
utilizzato per creare rappresentazioni diverse
– Singleton – fa in modo che una classe abbia una sola istanza e fornisce un
punto di accesso noto a tutti gli utilizzatori
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
6
Pattern Strutturali
• Descrivono come comporre classi e oggetti in strutture
più grandi
– Si dividono in: basati su classi e su oggetti
– I primi usano l’ereditarietà (statica)
– I secondi la composizione (anche dinamica)
• Conseguenze
– Aggiungono un livello di indirezione per disaccoppiare le due
interfacce.
• Esempi
–
–
–
–
–
Adapter
Composite
Decorator
Facade
Proxy – fornisce un surrogato di un oggetto per controllare l’accesso a
quest’ultimo
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
7
Pattern Comportamentali
• Riguardano algoritmi e l’assegnamento di responsabilità tra
oggetti
– Descrivono pattern di comunicazione tra oggetti.
– Per distribuire il comportamento usano l’ereditarietà o la composizione.
• Conseguenze
– Alcuni incapsulano il comportamento in modo da poterlo variare anche
dinamicamente
– Disaccoppiano il chiamante e il chiamato aggiungendo un livello di indirezione.
• Esempi
– Iterator– fornisce un modo per accedere agli elementi di un contenitore (un
oggetto aggregato) sequenzialmente senza esporre la struttura dati sottostante
– Mediator – definisce un oggetto che incapsula le strategie di collaborazione di
un gruppo di oggetti evitando che gli oggetti facciano riferimento l’uno all’altro
esplicitamente.
– Observer
– Strategy
– Visitor – rappresenta un’operazione da svolgersi sugli elementi di una struttura
di oggetti.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
8
Un possibile catalogo di Design Pattern (da Design Patterns –
elementi per il riuso di software a oggetti)
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
9
Relazioni tra Patterns (da Design Patterns –
elementi per il riuso di software a oggetti)
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
10
Design pattern in dettaglio
••Creazionali
Creazionali
••Factory
FactoryMethod
Method
••Abstract
AbstractFactory
Factory
••Strutturali
Strutturali
••Adapter
Adapter
••Composite
Composite
••Decorator
Decorator
••Facade
Facade
••Comportamentali
Comportamentali
••Observer
Observer
••Strategy
Strategy
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
11
Abstract Factory
• Scopo: definire un’interfaccia per la creazione di famiglie di
oggetti correlati o dipendenti senza specificare quali siano le
classi concrete.
• Motivazione: spesso ci si trova di fronte al problema di
voler istanziare un oggetto senza specificare precisamente la
classe. Comportamento chiaramente non possibile con
meccanismi di creazione tipo new.
• Applicabilità: utilizzato quando:
– sistema indipendente dalle modalità di creazione, composizione e
rappresentazione dei suoi prodotti;
– sistema configurabile dipendentemente dalle caratteristiche di una tra
piú tipologie di oggetto
– Si vuole fornire una libreria di classi rivelando solo interfaccia ma non
implementazioni specifiche
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
12
Abstract Factory – Struttura
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
13
Abstract Factory – Partecipanti
• AbstractFactory:
– Dichiara una interfaccia per le operazioni che creano e restituiscono i
prodotti.
– Nella dichiarazione di ogni metodo, i prodotti restituiti sono dei tipi
AbstractProduct.
• ConcreteFactory:
– Implementa l’AbstractFactory, fornendo le operazioni che creano e
restituiscono oggetti corrispondenti a prodotti specifici (ConcreteProduct).
• AbstractProduct:
– Dichiarano le operazioni che caratterizzano i diversi tipi generici di prodotti.
• ConcreteProduct:
– Definiscono i prodotti creati da ogni ConcreteFactory.
• Client:
– Utilizza l’AbstractFactory per rivolgersi alla ConcreteFactory di una
famiglia di prodotti.
– Utilizza i prodotti tramite la loro interfaccia AbstractProduct.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
14
Abstract Factory – Struttura di Esempio
•
•
•
Si pensi ad un dimostratore
dell’utilizzo di due famiglie di
prodotti, basate su tecnologie
diverse: nastro (tape) e CD.
Ogni famiglia è composta dal
supporto stesso (tape o cd),
un masterizzatore (recorder) e
un riproduttore (player).
Si vuole che un cliente sia in
grado di eseguire lo stesso
processo di prova su prodotti
di entrambe le famiglie.
Si deve definire un modo per
creare famiglie complete di
prodotti, senza vincolare alla
codifica del cliente che gli
utilizza, il codice delle
particolari famiglie.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
15
Abstract e Concrete Factory
public interface DevicesFactory {
}
public Player createPlayer();
public Recorder createRecorder();
public Media createMedia();
public class CDDevicesFactory implements DevicesFactory {
public Player createPlayer() {
return new CDPlayer();
}
public Recorder createRecorder() {
return new CDRecorder();
}
public Media createMedia() {
}
}
return new CD();
né l’AbstractFactory né gli
AbstractProduct implementano
operazioni Æ in Java diventa
più adeguato codificarli come
interfacce piuttosto che come
classi astratte.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
16
Classi appartenenti alla famiglia di prodotti CD:
CD, CDPlayer e CDRecorder
public class CD implements Media{
}
private String track = "";
public void writeOnDisk( String sound ) {
track = sound;
}
public class CDPlayer implements Player {
public String readDisk( ) {
CD cDInside;
return track;
public void accept( Media med ) {
}
cDInside = (CD) med;
}
public void play( ) {
if( cDInside == null )
System.out.println( "Error: No CD." );
else
System.out.println( cDInside.readDisk()
);
}
}
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
17
Client
class Client {
DevicesFactory technology;
public void selectTechnology( DevicesFactory df ) {
technology = df;
}
public void test(String song) {
Media media = technology.createMedia();
Recorder recorder = technology.createRecorder();
Player player = technology.createPlayer();
}
recorder.accept( media );
recorder.record( song );
player.accept( media );
player.play();
}
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
18
Istanza di un oggetto Client
public class AbstractFactoryExample {
public static void main ( String[] arg ) {
Client client = new Client();
System.out.println( “**Testing CD devices” );
client.selectTechnology( new CDDevicesFactory() );
client.test( “Moon river" );
}
}
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
19
Abstract Factory - Conseguenze
• Isola le classi concrete - i clienti non devono sapere niente delle classi
concrete che useranno, neanche al momento della creazione
• Grazie alle factory è possibile racchiudere la logica di creazione in un
unico modulo, delimitandola con precisione e permettendo così, nel
resto del programma, di stabilire effettivamente tra moduli dipendenze
basate unicamente su interfacce.
• È facile cambiare famiglia di prodotto basta cambiare la linea di
codice che riguarda la creazione della factory
• Promuove la consistenza tra i prodotti poiché i prodotti sono organizzati in
famiglie. I prodotti di una famiglia sono coordinati per lavorare insieme
• Supportare l’inserimento di un nuovo prodotto in una famiglia è difficile
poiché richiede cambiamenti all’Abstract Factory ed a tutte le sue
sottoclassi
• La creazione di oggetti non avviene nel modo standard Æ i clienti devono
sapere che devono usare la factory invece del costruttore per gli oggetti
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
20
Factory Method
• Definisce un’interfaccia per creare un oggetto, ma sono le sottoclassi che
decidono quale classe istanziare Æ Factory Method permette ad una
classe di delegare l’istanziazione alle sue sottoclassi
• Il pattern Factory Method incapsula la conoscenza di quali classi occorre
creare:
– Permette di scrivere una classe che delega la creazione degli oggetti
che usa, rendendola indipendente dalle rispettive classi
• Usare il pattern Factory Method quando
– Una classe non è in grado di anticipare quale classe di oggetti deve creare
– È desiderabile centralizzare la fase di creazione degli oggetti in una
classe dedicata (es. creazione di diversi tipi di documenti all’interno di
un’applicazione da ufficio quali documenti testuali, fogli di stile, ecc.)
– Il sistema usa classi astratte per definire e gestire relazioni tra oggetti
– Il sistema deve anche creare oggetti: deve istanziare le classi ma conosce solo
le classi astratte, che non può istanziare
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
21
Factory Method – Struttura e Partecipanti
• Product - Definisce l’interfaccia degli oggetti creati dal Factory Method
• ConcreteProduct - Implementa l’interfaccia del prodotto Product
• Creator
– Dichiara il Factory Method che restituisce l’oggetto di tipo Prodotto
– Può contenere un’implementazione di default del Factory Method
– Creator si basa sulle sue sottoclassi per definire il Factory Method in modo che
restituisca un’istanza del Concrete Product appropriato
• ConcreteCreator - Ridefinisce (override) il Factory Method per restituire
un’istanza di ConcreteProduct
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
22
Factory Method – Esempio
• Sistema per la
manipolazione di
elementi cartografici.
• Due classi astratte:
– classe Elemento
che rappresenta
qualunque tipo di
oggetto da
posizionare in una
mappa
– classe Strumento
che fornisce le
operazioni comuni di
manipolazione degli
Elementi.
• Il sistema sa quando un particolare tipo di elemento deve essere creato (ad
es., dopo aver richiesto un identificativo per un nuovo elemento), ma non il
tipo particolare di Elemento a creare.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
23
Factory Method - Conseguenze
• La classe che richiede la creazione è indipendente
dalle classi degli oggetti “concrete product” che
utilizza
• Utilizzare un metodo factory per la creazione di
oggetti di una classe fornisce sempre una flessibilità
maggiore rispetto alla creazione diretta dell’oggetto
– È possibile usare il pattern Factory Method come metodo
standard per la creazione di oggetti?
• L’insieme degli oggetti “concrete product” che
possono essere creati può cambiare dinamicamente
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
24
Adapter
• Utile quando bisogna connettere diversi elementi eterogenei
poichè adatta l’interfaccia di un elemento di un sistema (adaptee)
ad una forma richiesta da uno dei suoi client
• Converte l’interfaccia di una classe in un’altra interfaccia richiesta dal
client Æ consente a classi diverse di operare insieme quando ciò non
sarebbe altrimenti possibile a causa di interfacce incompatibili (es. il
client è .NET mentre l’adaptee è Java)
• È un“adattatore” che separa client e adaptee:
– Comunicazioni tra client e adaptee sono gestite dall’adapter
– il ruolo dell’adattatore è semplicemente di interpretare le richieste del
client, trasformarle in richieste all’adaptee, ottenere risposte
dall’adaptee, trasformarle in risposte al client
– l’adattatore ha in generale un’interfaccia (target) diversa da quella
dell’adaptee
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
25
Adapter – Struttura
Ereditarietà Multipla
Composizione di oggetti
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
26
Adapter – Esempio
public class RectangleObjectAdapter implements Polygon{
Rectangle adaptee;
private String name = "NO NAME";
public RectangleObjectAdapter() {
adaptee = new Rectangle();
}
public void define( float x0, float y0, float x1, float y1,String col ){
float a = x1 - x0;
float l = y1 - y0;
adaptee.setShape( x0, y0, a, l, col);
}
public float getSurface() {
return adaptee.getArea();
}
public float[] getCoordinates() {
float aux[] = new float[4];
aux[0] = adaptee.getOriginX();
aux[1] = adaptee.getOriginY();
aux[2] = adaptee.getOppositeCornerX();
aux[3] = adaptee.getOppositeCornerY();
return aux;
}
public void setId( String id ) {
name = id;
}
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
27
Adapter - Conseguenze
• disaccoppiamento delle implementazioni del client e
dell’adaptee – l’implementazione di ciascun elemento può
variare senza che questo si ripercuota sull’altro elemento
• l’adaptee può essere usato da diversi tipi di client ciascuno
col suo adattatore
• l’indirezione addizionale potrebbe ridurre l’efficienza
– ci potrebbe essere un aumento nell’overhead per la manutenzione
– se cambia il servizio offerto dall’adaptee – e quindi oltre all’adaptee
(ed eventualmente al client) deve cambiare anche l’adattatore
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
28
Composite
• Compone oggetti in strutture ad albero per rappresentare
gerarchie di componenti
– Oggetti singoli e composti vengono trattati uniformemente
– Si possono aggiungere altri componenti alla gerarchia senza
influenzare gli altri
• Consente la costruzione di gerarchie di oggetti composti. Gli
oggetti composti possono essere formati da oggetti singoli, oppure
da altri oggetti composti.
• Questo pattern è utile nei casi in cui si vuole:
– Rappresentare gerarchie di oggetti tutto-parte.
– Essere in grado di ignorare le differenze tra oggetti singoli e oggetti
composti.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
29
Composite – Struttura e Partecipanti
•
Component:
–
–
•
Leaf:
–
–
•
Estende la classe Component, per
rapperesentare gli oggetti che non
sono composti (foglie).
Implementa le operazioni per questi
oggetti.
Composite:
–
–
–
•
Dichiara una interfaccia comune per
oggetti singoli e composti.
Implementa le operazioni di default o
comuni tutte le classi.
Estende la classe Component, per
rappresentare gli oggetti che sono
composti.
Immagazzina al suo interno i propri
componenti.
Implementa le operazioni proprie degli
oggetti composti, e particolarmente
quelle che riguardano la gestione dei
propri componenti.
Client: Utilizza gli oggetti singoli e
composti tramite l’interfaccia
rappresentata dalla classe astratta
Component.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
30
Composite – Esempio 1
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
31
Composite – Esempio 2
•
•
•
•
•
Consideriamo l’organizzazione di un documento suddiviso in capitoli e paragrafi rappresentati
da altrettanti oggetti il cui tipo base è la classe astratta DocumentElement
Ciascun capitolo (classe DocumentChapter) è un elemento composito che contiene uno o più
paragrafi. L’elemento “foglia” della struttura del documento è rappresentato dal paragrafo
(classe DocumentParagraph).
L’implementazione interna dell’elemento “paragrafo” è differente da quella dell’elemento
composito (il capitolo).
Si noti inoltre che nulla vieta che un capitolo possa a sua volta contenere uno o più
sottocapitoli sempre di tipo DocumentChapter.
Si noti infine come l’aggiunta di una nuova tipologia di elemento (per esempio, una
ipotetica classe DocumentSection) non rappresenti un grosso problema, dal momento che la
struttura è pensata per evolvere in modo flessibile nel tempo.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
32
Composite - Conseguenze
• Definisce gerarchie di classi costituite da oggetti primitivi e
composti in modo del tutto trasparente al client che potrà
utilizzarli indifferentemente
• Semplifica il client: non è necessario scrivere “blocchi case”
per distinguere tra oggetti semplici e composti poiché tutti gli
oggetti hanno un’interfaccia uniforme
• Rende più semplice l’aggiunta di nuove tipologie di
componenti
• Può rendere il progetto troppo generico – se si vuole che la
struttura composita contenga solo alcuni componenti?
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
33
Decorator
• Aggiunge dinamicamente responsabilità addizionali ad un
oggetto. In questo modo si possono estendere le funzionalità
d’oggetti particolari senza coinvolgere complete classi.
• Per assegnare responsabilità a singoli oggetti, in maniera dinamica
e trasparente (cioè senza coinvolgere altri oggetti)
• Utile quando l’estensione attraverso la specializzazione è
sconveniente.
• Esempio: vogliamo che una text box abbia anche una scrollbar
• Problema: vogliamo che questa estensione venga decisa
dinamicamente, durante l’esecuzione Æ non si vuole quindi ricorrere alla
specializzazione
• Soluzione:
– incapsulare l’oggetto principale (nel nostro esempio, la text box) in un altro
oggetto chiamato decorator (nel nostro esempio, la scrollbar)
– Il decorator deve fornire servizi conformi con quelli forniti dall’oggetto
principale
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
34
Decorator – Struttura e Partecipanti
• Component: Specifica l’interfaccia degli oggetti che possono avere delle
responsabilità aggiunte dinamicamente.
• ConcreteComponent: Implementa l’oggetto in cui si possono aggiungere
nuove responsabilità.
• Decorator: Possiede un riferimento all’oggetto Component e specifica
un’interfaccia concordante con l’interfaccia Component.
• ConcreteDecorator: Aggiunge nuove responsabilità al Component.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
35
Decorator – Esempio
• Esiste un modello di
oggetti che rappresenta gli
impiegati (Employee) di
una azienda.
• Il sistema comprende la
possibilità di investire gli
impiegati con delle
responsabilità aggiuntive.
• È necessario definire un
modo per aggiungere
dinamicamente nuove
responsabilità ad oggetto
specifico.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
36
Decorator – Esempio
abstract class ResponsibleWorker implements Employee {
protected Employee responsible;
public ResponsibleWorker(Employee employee) {
responsible = employee;
}
public String getName() {
return responsible.getName();
}
public String getOffice() {
return responsible.getOffice();
}
public void whoIs() {
responsible.whoIs();
}
}
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
37
Decorator – Esempio
public class ProjectManager extends ResponsibleWorker {
private String project;
public ProjectManager( Employee empl, String proj ) {
super( empl );
project = proj;
public class DecoratorExample1 {
}
public static void main(String arg[]) {
public void whoIs() {
Employee one = new Engineer( “John Doe",
"Programming Department" );
super.whoIs();
System.out.println( "I am the
one = new AdministrativeManager(one);
Manager of the Project:" + project );
}
one = new ProjectManager(one,
}
“Project1" );
one = new ProjectManager( one,
“Project2" );
}
}
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
38
Decorator - Conseguenze
• Maggiore flessibilità dell’ereditarietà
– Il pattern Decorator fornisce un sistema più flessibile di quello che si
otterrebbe con l’ereditarietà (eventualmente multipla).
– Con il Decorator le responsabilità possono essere aggiunte e rimosse a
run-time (mutando dei riferimenti).
• Funzionalità complesse ottenute mediante aggregazione di
piccoli semplici pezzi
• Le funzionalità possono essere attivate in maniera mirata. Ciò
evita di avere un’unica classe che prevede tutte le possibili
estensioni (complessa e inefficiente)
• Eccesso di piccole classi simili tra di loro
– Ciò rende il codice più complesso da comprendere e da manutenere
per chi non conosce bene le varie classi Decorator
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
39
Facade
• Obiettivi
– Fornire un’interfaccia semplice per moduli/componenti internamente
complessi
– Garantire il disaccoppiamento tra i moduli/componenti poiché
minimizza la comunicazione e la dipendenza tra sottosistemi
– Offrire un meccanismo di layering
• Soluzione
– Raggruppare i servizi che un modulo/componente offre all’esterno in
un’unica classe che rappresenta la “facciata” del modulo/componente
– Definisce un’interfaccia ad un più alto livello di astrazione che rende il
sottosistema più semplice da utilizzare
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
40
Facade – Struttura e partecipanti
•
Facade:
– Ha conoscenza delle funzionalità di ogni classe del sottosistema.
– Delega agli appropriati oggetti del sottosistema ogni richiesta pervenuta dall’esterno.
•
Subsystem classes:
– Implementano le funzionalità del sottosistema
– Gestiscono le attività assegnate dal Facade.
– Non hanno riferimenti verso il Facade.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
41
Facade - Conseguenze
• Favorisce l’incapsulamento - Nasconde ai client i
componenti del sottosistema
• Promuove l’accoppiamento lasco fra un sottosistema ed i
sui client (particolarmente utile quando vengono
implementati in modo indipendente)
• Non impedisce ai client di utilizzare le classi del sottosistema
direttamente qualora sia necessario.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
42
Observer (o Publisher/Subscriber)
•
•
utile quando un elemento (publisher) crea informazioni che sono di
interesse per altri elementi (subscriber)
L’intento del pattern Observer è definire una dipendenza uno-a-molti tale che
quando un oggetto cambia stato tutti quelli che ne dipendono vengono
automaticamente notificati del fatto ed aggiornati di conseguenza
–
L’oggetto osservato è chiamato Subject (soggetto) mentre gli oggetti osservatori sono
noti come Observer
•
ciascun subscriber dovrebbe reagire in un modo proprio quando un
publisher genera un evento mentre il publisher dovrebbe mantenere un
accoppiamento basso verso i suoi subscriber
•
Il problema è trovare un modo col quale gli eventi dell’oggetto di
riferimento, siano comunicati a tutti gli altri interessati.
•
il publisher registra dinamicamente i subscriber che sono interessati ai
suoi eventi e avvisa quando si verifica un evento secondo 2 modalità:
1. la notifica contiene tutti i dettagli dell’evento
2. notifica che “qualcosa è cambiato” – poi il subscriber, se interessato, interroga
il publisher
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
43
Observer – Struttura e partecipanti
•
•
•
•
Subject:
– Ha conoscenza dei propri
Observer
– Fornisce operazioni per
l’addizione e cancellazione di
oggetti Observer.
– Fornisce operazioni per la
notifica agli Observer.
Observer: Specifica una
interfaccia per la notifica di eventi
agli oggetti interessati in un
Subject
ConcreteSubject:
– Possiede uno stato
dell’interesse dei
ConcreteSubject.
– Invoca le operazioni di notifica
ereditate dal Subject, quando
devono essere informati i
ConcreteObserver.
ConcreteObserver: Implementa
l’operazione di aggiornamento
dell’Observer.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
44
Applicabilità del pattern Observer - Esempio
• Esiste una classe ListaStudenti che mantiene una lista di
Studenti iscritti all'esame di Ingegneria del Software, con
metodi per l'aggiornamento della stessa
• Esiste una classe MatricoleWindow che si occupa della
visualizzazione del listato delle matricole mentre un'altra
classe DetailsWindow si occupa della visualizzazione di nomi,
cognomi, matricole, e contatore finale di iscritti
• MatricoleWindow e DetailsWindow sono Observer del
Subject ListaStudenti:
– ListaStudenti invocherà setChanged() se è stato aggiunto o rimosso
uno studente o ne sono stati modificati i dati, e lo notificherà a tutti
gli Observer
– MatricoleWindow aggiornerà il listato
– DetailsWindow farà lo stesso, e in più aggiornerà anche il contatore,
se è stato aggiunto o rimosso uno studente
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
45
Implementazione in Java
• Java fornisce già implementate le classi per realizzare il pattern Observer
– Gli osservatori devono implementare l’interfaccia java.util.Observer la quale
definisce il metodo
• public void update(Observable o,Object arg)
– Il subject per essere tale deve estendere la classe java.util.Observable che
tra gli altri fornisce i seguenti metodi:
Esistono due segnature
– public void addObserver(Observer o)
una senza argomenti e
– public void removeObserver(Observer o)
l’altra richiede un Object
– public void notifyObserver([Object arg])
come argomento
– Protected void setChanged()
• Il subject notifica il cambiamento dello stato invocando notifyObserver il
quale chiama i metodi update degli osservatori installati quando vengono
chiamati in sequenza
• Si intende che il subject cambia stato quando viene chiamato il metodo
setChanged
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
46
Observer – conseguenze
• accoppiamento debole (astratto e minimale) tra il publisher e
i suoi subscriber
– supporto per comunicazione broadcast
– possibilità di aggiungere/rimuovere subscriber dinamicamente
• potrebbe essere difficile comprendere le relazioni di
dipendenza tra i vari elementi
• effetto imprevedibile degli aggiornamenti – una modifica in
un publisher può scatenare una catena di aggiornamenti e
sincronizzazioni su tutti i subscriber
• implementazione complessa – se è richiesta una consegna
affidabile dei messaggi
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
47
Strategy
• Consente la definizione di una famiglia d’algoritmi,
incapsula ognuno e gli fa intercambiabili fra di loro. Questo
permette modificare gli algoritmi in modo indipendente dai
clienti che fanno uso di essi.
• Lo “Strategy” pattern suggerisce l’incapsulazione della logica
di ogni particolare algoritmo, in apposite classi che
implementano l’interfaccia che consente agli oggetti “client” di
interagire con loro.
• Utile quando
– Sono necessarie più varianti di un algoritmo (diverse strategie per
occupazione di memoria, velocità di esecuzione, ecc.)
– L’algortimo usa strutture dati complesse che si vogliono nascondere al
client
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
48
Strategy – Struttura e partecipanti
• Strategy: Dichiara
un’interfaccia comune per tutti
gli algoritmi supportati. Il
Context utilizza questa
interfaccia per invocare gli
algoritmi definiti in ogni
ConcreteStrategy.
• ConcreteStrategy:
Implementano gli algoritmi che
usano l’interfaccia Strategy.
• Context:
– Viene configurato con un
oggetto ConcreteStrategy e
mantiene un riferimento verso
esso.
– Può specificare un’interfaccia
che consenta alle Strategy di
accedere ai propri dati.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
49
Strategy – Esempio
• Il sistema offre delle funzionalità matematiche, mediante l’apposita classe
MyArray per la rappresentazione di vettori di numeri mentre la stampa del
vettore può avvenire secondo diverse modalità
• Il problema è trovare un modo di isolare l’algoritmo che formatta e stampa
il contenuto dell’array, per farlo variare in modo indipendente dal resto
dell’implementazione della classe.
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
50
Strategy – Esempio
public class MyArray {
private int[] array;
private int size;
ArrayDisplayFormat format;
public MyArray( int size ) {
array = new int[ size ];
}
public void setValue( int pos, int value ) {
array[pos] = value;
}
public int getValue( int pos ) {
return array[pos];
}
public int getLength( int pos ) {
return array.length;
}
public void setDisplayFormat( ArrayDisplayFormat adf )
{
format = adf;
}
public void display() {
format.printData( array );
}
}
public class StrategyExample {
public static void main (String[] arg) {
MyArray m = new MyArray( 10 );
m.setValue( 1 , 6 );
m.setValue( 0 , 8 );
m.setValue( 4 , 1 );
m.setValue( 9 , 7 );
m.setDisplayFormat( new StandardFormat() );
m.display();
m.setDisplayFormat( new MathFormat() );
m.display();
}
}
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
51
Strategy - Conseguenze
• Gestire con maggiore flessibilità una famiglia di algoritmi
correlati mediante una gerarchia di classi strategy
• Offrire un’alternativa all’ereditarietà – si potrebbe estendere
direttamente una classe context per ottenere un
comportamento diverso ma questo approccio lega
staticamente il comportamento nel context e mescola
l’implemenatzione del context con quella dell’algoritmo
• I client devono conoscere le diverse strategy disponibili Æ è
bene utilizzare il pattern Strategy solo quando le varianti di
comportamento sono richieste dal client (eliminando blocchi
“case” dal client)
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
52
Pattern (Idiomi) and Layers
• Livello di Presentazione
– I check sugli input e sugli output sono incorporati nelle view
(Intercepting Filter)
– La gestione delle richieste non è centralizzata (Front controller)
• accesso indiscriminato sugli altri livelli
• logica di navigazione diffusa su tutte le viste
– Le viste presentano delle sezioni comuni quali header, ricerca,
autenticazione, carrello, ecc. (Composite View)
• Nel livello di dominio
– I servizi di dominio non sono gestiti in maniera centralizzata per es. il
flusso applicativo è gestito dalle stesse classi che offrono le funzionalità
(Facade)
• Sorgente Dati
– Le classi di dominio del sistema accedono direttamente al database
(DAO)
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
53
Patterns and Model-View-Controller
• MVC disaccoppia le viste dai modelli:
– Disaccoppia gli oggetti, in modo che cambiare un oggetto che influenza
molti altri oggetti non richiede all’oggetto di conoscere i dettagli degli
altri ( pattern Observer )
• MVC permette di annidare le views:
– Il pattern Composite descrive il problema più generale di raggruppare
oggetti primitivi e compositi in nuovi oggetti con interfacce identiche
• MVC controlla la vista mediante il controller ( pattern
Strategy )
• MVC usa inoltre i pattern Factory Method e Decorator
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
54
Pattern e Specifiche dei Requisiti
• R. : “indipendente dal costruttore HW”, “indipendente
dal dispositivo”, “deve supportare una famiglia di
prodotti” Æ Abstract Factory Pattern
• R. : “deve interfacciare un oggetto pre-esistente” Æ
Adapter Pattern
• R. : “struttura complessa”, “deve avere parametri
variabili” Æ Composite Pattern
• R. : “deve interfacciare un insieme di oggetti di un
sotto-sistema” Æ Façade Pattern
• R. : “deve essere estendibile”, “deve essere scalabile”
Æ Observer Pattern
• R. : “deve fornire politiche indipendenti dai meccanismi
di realizzazione” Æ Strategy Pattern
E. TINELLI – Ingegneria del Software A. A. 20082008-2009
55
Scarica

Design Pattern