design pattern comportamentali
TRANSCRIPT
DESIGN PATTERN COMPORTAMENTALIINGEGNERIA DEL SOFTWAREUniversità degli Studi di Padova
Dipartimento di Matematica
Corso di Laurea in Informatica, A.A. 2014 – 2015
Ingegneria del software mod. A
INTRODUZIONE
2Riccardo Cardin
Architetturali
Model view controller
Ingegneria del software mod. A
INTRODUZIONE
Scopo dei design pattern comportamentali
In che modo un oggetto svolge la sua funzione?
In che modo diversi oggetti collaborano tra loro?
3Riccardo Cardin
Ingegneria del software mod. A
COMMAND
Scopo
Incapsulare una richiesta in un oggetto, cosicché i client sia indipendenti dalle richieste
Motivazione
Necessità di gestire richieste di cui non si conoscono i particolari Toolkit associano ai propri elementi, richieste da eseguire
Una classe astratta, Command, definisce l’interfaccia per eseguire la richiesta La richiesta è un semplice oggetto
4Riccardo Cardin
Ingegneria del software mod. A
COMMAND
Applicabilità
Parametrizzazione di oggetti sull’azione da eseguire Callback function
Specificare, accodare ed eseguire richieste molteplici volte
Supporto ad operazione di Undo e Redo
Supporto a transazione Un comando equivale ad una operazione atomica
5Riccardo Cardin
Ingegneria del software mod. A
COMMAND
Struttura
6Riccardo Cardin
Interfaccia di esecuzione
delle richieste
Implementa la
richiesta
concreta,
invocando
l’operazione
sul receiver
Esegue il comando
Conosce come portare a
termine la richiesta del
comando concreto
Ingegneria del software mod. A
COMMAND
Struttura
7Riccardo Cardin
Ingegneria del software mod. A
COMMAND
Conseguenze
Accoppiamento “lasco” tra oggetto invocante e quello che porta a termine l’operazione
I command possono essere estesi
I comandi possono essere composti e innestati
È facile aggiungere nuovi comandi Le classi esistenti non devono essere modificate
8Riccardo Cardin
Ingegneria del software mod. A
COMMAND
Esempio
9Riccardo Cardin
Esempio
Una classe Account modella conti correnti. Le funzionalità che si
vogliono realizzare sono:
- Prelievo
- Versamento
- Undo
Questa operazione consente di annullare una delle precedenti, ma con
il vincolo che l’annullamento deve avvenire con ordine cronologico
inverso.
Ingegneria del software mod. A
COMMAND
Esempio
10Riccardo Cardin
Ingegneria del software mod. A
COMMAND
Esempio
Scala: first order function
11Riccardo Cardin
object Invoker {
private var history: Seq[() => Unit] = Seq.empty
def invoke(command: => Unit) { // by-name parameter
command
history :+= command _
}
}
Invoker.invoke(println("foo"))
Invoker.invoke {
println("bar 1")
println("bar 2")
}
È possibile sostituire il command
con oggetti funzione: maggior
concisione, ma minor
configurabilità
Parametro by-name
Ingegneria del software mod. A
COMMAND
Esempio
Javascript: utilizzo oggetti funzione e apply
12Riccardo Cardin
(function(){
var CarManager = {
// request information
requestInfo: function( model, id ) { /* ... */ },
// purchase the car
buyVehicle: function( model, id ) { /* ... */ },
// arrange a viewing
arrangeViewing: function( model, id ){ /* ... */ }
};
})();
CarManager.execute = function ( name ) {
return CarManager[name] && CarManager[name].apply( CarManager,
[].slice.call(arguments, 1) );
};
CarManager.execute( "buyVehicle", "Ford Escort", "453543" );
Rende uniforme l’API,
utilizzando il metodo
apply
Trasforma l’oggetto
arguments in un array
Ingegneria del software mod. A
COMMAND
Implementazione
Quanto deve essere intelligente un comando? Semplice binding fra il receiver e l’azione da eseguire
Comandi agnostici, autoconsistenti
Supporto all’undo e redo Attenti allo stato del sistema da mantenere (receiver,
argomenti, valori originali del sistema …)
History list
Accumulo di errori durante l’esecuzione di più comandi successivi
Utilizzo dei template C++ o dei Generics Java
13Riccardo Cardin
Ingegneria del software mod. A
ITERATOR
Scopo
Fornisce l’accesso sequenziale agli elementi di un aggregato Senza esporre l’implementazione dell’aggregato
Motivazione
“Per scorrere non è necessario conoscere” Devono essere disponibili diverse politiche di
attraversamento
Iterator pattern sposta la responsabilità di attraversamento in un oggetto iteratore Tiene traccia dell’elemento corrente
14Riccardo Cardin
Ingegneria del software mod. A
ITERATOR
Applicabilità
Accedere il contenuto di un aggregato senza esporre la rappresentazione interna
Supportare diverse politiche di attraversamento
Fornire un’interfaccia unica di attraversamento su diversi aggregati Polymorphic iteration
15Riccardo Cardin
Ingegneria del software mod. A
ITERATOR
Struttura
16Riccardo Cardin
Interfaccia per accedere e
attraversare gli aggregati
Tiene traccia della posizione
corrente nell’attraversamento
dell’aggregato
Interfaccia di creazione
degli iteratori (factory
method) Ritorna un’istanza di
un iteratore concreto
Ingegneria del software mod. A
ITERATOR
Conseguenze
Supporto a variazioni nelle politiche di attraversamento di un aggregato
Semplificazione dell’interfaccia dell’aggregato
Attraversamento contemporaneo di più iteratori sul medesimo aggregato
17Riccardo Cardin
Ingegneria del software mod. A
ITERATOR
Esempio
18Riccardo Cardin
Esempio
Vediamo alcuni esempi di implementazione del pattern nella libreria
J2SE di Java
Ingegneria del software mod. A
ITERATOR
Esempio
19Riccardo Cardin
// preparo ed eseguo una query con JDBC
String sql = “select * from utenti where user = ?”;
PreparedStatement pst = connection.prepareStatement(sql);
pst.setString(1,x);
ResultSet rs = pst.executeQuery();
// ciclo i risultati con un generico iteratore
while(rs.next()) {
Utente utente = new Utente();
utente.setUser(rs.getString(“user”));
utente.setPassword(rs.getString(“password”));
// ...
}// creo un aggregatore concreto
List<Employee> lista = new ArrayList<Employee>();
lista.add(new Employee(…));
lista.add(new Employee(…));
// ciclo tramite un generico iteratore
Iterator iterator = lista.iterator();
while(iterator.hasNext()) {
Employee e = iterator.next();
System.out.print(e.getNome() + " guadagna ");
System.out.println(e.getSalario());
}
java.util.Iterator
java.sql.ResultSet
Ingegneria del software mod. A
ITERATOR
Implementazione Chi controlla l’iterazione?
External (active) iterator: il client controlla l’iterazione
Internal (passive) iterator: l’iteratore controlla l’iterazione
Chi definisce l’algoritmo di attraversamento? Aggregato: iteratore viene definito “cursore”
Il client invoca Next sull’aggregato, fornendo il cursore
Iteratore: viene violata l’encapsulation dell’aggregato
Miglior riuso degli algoritmi di attraversamento
Iteratori robusti Assicurarsi che l’inserimento e la cancellazione di elementi
dall’aggregato non creino interferenze
20Riccardo Cardin
Ingegneria del software mod. A
ITERATOR
Implementazione
Operazioni aggiuntive
Polymorphic iterator Utilizzo del Proxy Pattern per deallocazione dell’iteratore
Accoppiamento stretto tra iteratore e aggregato C++, dichiarare friend l’iteratore
Null Iterator Iteratore degenere che implementa IsDone con il ritorno di true
Utile per scorrere strutture ricorsive
21Riccardo Cardin
Ingegneria del software mod. A
OBSERVER
Scopo Definisce una dipendenza “1..n” fra oggetti,
riflettendo la modifica di un oggetto sui dipendenti
Motivazione Mantenere la consistenza fra oggetti
Modello e viste ad esso collegate
Observer pattern definisce come implementare la relazione di dipendenza Subject: effettua le notifiche
Observer: si aggiorna in risposta ad una notifica
“Publish - Subscribe”
22Riccardo Cardin
Ingegneria del software mod. A
OBSERVER
Motivazione
23Riccardo Cardin
Ingegneria del software mod. A
OBSERVER
Applicabilità
Associare più “viste” differenti ad una astrazione Aumento del grado di riuso dei singoli tipi
Il cambiamento di un oggetto richiede il cambiamento di altri oggetti Non si conosce quanti oggetti devono cambiare
Notificare oggetti senza fare assunzioni su quali siano questi oggetti Evita l’accoppiamento “forte”
24Riccardo Cardin
Ingegneria del software mod. A
OBSERVER
Struttura
25Riccardo Cardin
Interfaccia di
sottoscrizione,
eliminazione e notifica
Interfaccia di aggiornamento
degli oggetti che possono
essere notificati
Mantiene lo stato di
cui viene data una
“vista” concreta
Ha un riferimento al
soggetto concreto e
possiede lo stato che deve
essere aggiornato
Ingegneria del software mod. A
OBSERVER
Struttura
26Riccardo Cardin
Modifica e notifica
Aggiornamento delle
“viste”
Ingegneria del software mod. A
OBSERVER
Conseguenze
Accoppiamento “astratto” tra soggetti e osservatori I soggetti non conoscono il tipo concreto degli osservatori
Comunicazione broadcast Libertà di aggiungere osservatori dinamicamente
Aggiornamenti non voluti Un operazione “innocua” sul soggetto può provocare una
cascata “pesante” di aggiornamenti
Gli osservatori non sanno cosa è cambiato nel soggetto …
27Riccardo Cardin
Ingegneria del software mod. A
OBSERVER
Esempio
28Riccardo Cardin
Esempio
Modifica di una o più aree di finestre in risposta alla pressione di un
pulsante (Java Swing)
Ingegneria del software mod. A
OBSERVER
Esempio
29Riccardo Cardin
• Il costruttore della classe JFrame possiede l’istruzione bottone.addActionListener(this)
• L’utente clicca sul pulsante e il metodo segnala viene invocato
• Il metodo segnala invoca il metodo actionPerformed su tutti gli oggetti presenti nel vettore
“ascoltatori”
Ingegneria del software mod. A
OBSERVER
Implementazione
Utilizzo di sistemi di lookup per gli osservatori Nessun spreco di memoria nel soggetto
Osservare più di un soggetto alla volta Estendere l’interfaccia di aggiornamento con il soggetto che
ha notificato
Chi deve attivare l’aggiornamento delle “viste”? Il soggetto, dopo ogni cambiamento di stato
Il client, a termine del processo di interazione con il soggetto
Evitare puntatori “pendenti” (dangling)
Notificare solo in stati consistenti Utilizzo del Template Method pattern
30Riccardo Cardin
Ingegneria del software mod. A
OBSERVER
Implementazione Evitare protocolli di aggiornamento con assunzioni
Push model: il soggetto conosce i suoi osservatori
Pull model: il soggetto invia solo la notifica
Notifica delle modifiche sullo stato del soggetto Gli osservatori si registrano su un particolare evento
Unificare le interfacce di soggetto e osservatore Linguaggi che non consento l’ereditarietà multipla
Smalltalk, ad esempio …
31Riccardo Cardin
void Subject::Attach(Observer*, Aspect& interest)
void Observer::Update(Subject*, Aspect& interest)
Ingegneria del software mod. A
STRATEGY
Scopo Definisce una famiglia di algoritmi, rendendoli
interscambiabili Indipendenti dal client
Motivazione Esistono differenti algoritmi (strategie) che non
possono essere inserite direttamente nel client I client rischiano di divenire troppo complessi
Differenti strategie sono appropriate in casi differenti
È difficile aggiungere nuovi algoritmi e modificare gli esistenti
32Riccardo Cardin
Ingegneria del software mod. A
STRATEGY
Applicabilità
Diverse classi differiscono solo per il loro comportamento
Si necessita di differenti varianti dello stesso algoritmo
Un algoritmo utilizza dati di cui i client non devono occuparsi
Una classe definisce differenti comportamenti, tradotti in un serie di statement condizionali
33Riccardo Cardin
Ingegneria del software mod. A
STRATEGY
Struttura
34Riccardo Cardin
Interfaccia supportata da
tutti gli algoritmi
Implementazione concreta
di un algoritmo
Configurato con una
strategia concreta. Può
definire un’interfaccia per
l’accesso ai propri dati
Ingegneria del software mod. A
STRATEGY
Conseguenze
Definizione di famiglie di algoritmi per il riuso del contesto
Alternativa all’ereditarietà dei client Evita di effettuare subclassing direttamente dei contesti
Eliminazione degli statement condizionali
35Riccardo Cardin
void Composition::Repair() {
switch (_breakingStrategy) {
case SimpleStrategy:
ComposeWithSimpleCompositor();
break;
case TeXStrategy:
ComposeWithTeXCompositor();
break;
// ...
}
}
void Composition::Repair() {
_compositor->Compose();
// merge results with existing
// composition, if necessary
}
Ingegneria del software mod. A
STRATEGY
Conseguenze
Differenti implementazioni dello stesso comportamento
I client a volte devono conoscere dettagli implementativi … per poter selezionare il corretto algoritmo …
Comunicazione tra contesto e algoritmo Alcuni algoritmi non utilizzano tutti gli input
Incremento del numero di oggetti nell’applicazione
36Riccardo Cardin
Ingegneria del software mod. A
STRATEGY
Esempio
37Riccardo Cardin
Esempio
Si vuole realizzare una classe MyArray per disporre di tutte le funzioni
utili per lavorare con vettori di numeri. Si prevedono 2 funzioni di
stampa:
- Formato matematico { 67, -9, 0, 4, …}- Formato standard Arr[0] = 67 Arr[1] = -9 Arr[2] = 0 ...
Questi formati potrebbero, in futuro, essere sostituiti o incrementati
Ingegneria del software mod. A
STRATEGY
Esempio
38Riccardo Cardin
Ingegneria del software mod. A
STRATEGY
Esempio Scala: first-class functions
Le funzioni sono tipi Possono essere assegnate a variabili
_ è una wildcard ed equivale ad un parametro differente per ogni occorrenza
39Riccardo Cardin
type Strategy = (Int, Int) => Int
class Context(computer: Strategy) {
def use(a: Int, b: Int) { computer(a, b) }
}
val add: Strategy = _ + _
val multiply: Strategy = _ * _
new Context(multiply).use(2, 3)
Definizione di un tipo
funzione
Implementazioni
possibili Strategy
Ingegneria del software mod. A
STRATEGY
Implementazione
Definire le interfacce di strategie e contesti Fornisce singolarmente i dati alle strategie
Fornire l’intero contesto alle strategie
Inserire un puntamento al contesto nelle strategie
Implementazione strategie C++: Template, Java: Generics
Solo se l’algoritmo può essere determinato a compile time e non può variare dinamicamente
Utilizzo strategia opzionali Definisce una strategia di default
40Riccardo Cardin
Ingegneria del software mod. A
TEMPLATE METHOD
Scopo
Definisce lo scheletro di un algoritmo, lasciando l’implementazione di alcuni passi alle sottoclassi Nessuna modifica all’algoritmo originale
Motivazione
Definire un algoritmo in termini di operazioni astratte Viene fissato solo l’ordine delle operazioni
Le sottoclassi forniscono il comportamento concreto
41Riccardo Cardin
Ingegneria del software mod. A
TEMPLATE METHOD
Applicabilità
Implementare le parti invarianti di un algoritmo una volta sola
Evitare la duplicazione del codice Principio “refactoring to generalize”
Controllare le possibili estensioni di una classe Fornire sia operazioni astratte sia operazioni hook (wrapper)
42Riccardo Cardin
Ingegneria del software mod. A
TEMPLATE METHOD
Struttura
43Riccardo Cardin
Definisce le operazione astratte
primitive. Definisce lo scheletro
dell’algoritmo
Implementa le operazioni
primitive fornendo i passi
concreti all’algoritmo
Ingegneria del software mod. A
TEMPLATE METHOD
Conseguenze
Tecnica per il riuso del codice Fattorizzazione delle responsabilità
“The Hollywood principle”
Tipi di operazioni possibili Operazioni concrete della classe astratta
Operazioni primitive (astratte)
Operazioni hook
Forniscono operazioni che di default non fanno nulla, ma rappresentano punti di estensione
Documentare bene quali sono operazioni primitive e quali hook
44Riccardo Cardin
Ingegneria del software mod. A
TEMPLATE METHOD
Esempio
45Riccardo Cardin
Esempio
Si vuole realizzare un set di funzioni per effettuare operazioni sugli
array. Si prevedono 2 funzioni aritmetiche:
- Somma di tutti gli elementi
- Prodotto di tutti gli elementi
Ingegneria del software mod. A
TEMPLATE METHOD
Esempio
Soluzione naive
46Riccardo Cardin
public int somma(int[] array) {
int somma = 0;
for (int i = 0; i < array.length; i++) {
somma += array[i];
}
return somma;
}
public int prodotto(int[] array){
int prodotto= 1;
for (int i = 0; i < array.length; i++) {
prodotto *= array[i];
}
return prodotto;
}
Ingegneria del software mod. A
TEMPLATE METHOD
Esempio
Soluzione con Template Method pattern
47Riccardo Cardin
public abstract class Calcolatore {
public final int calcola(int[] array){
int value = valoreIniziale();
for (int i = 0; i < array.length; i++) {
value = esegui(value, array[i]);
}
return value;
}
protected abstract int valoreIniziale();
protected abstract int esegui(int currentValue, int element);
}
public class CalcolatoreSomma {
protected int esegui(int currentValue, int element) {
return currentValue + element;
}
protected int valoreIniziale() {
return 0;
}
}
Ingegneria del software mod. A
TEMPLATE METHOD
Esempio
Scala: idioma, utilizzo high order function
Utilizzo metodi map, forall, flatMap, ...
Monads
...
48Riccardo Cardin
def doForAll[A, B](l: List[A], f: A => B): List[B] = l match {
case x :: xs => f(x) :: doForAll(xs, f)
case Nil => Nil
}
// Already in Scala specification
List(1, 2, 3, 4).map {x => x * 2}
Ingegneria del software mod. A
TEMPLATE METHOD
Esempio
Javascript: utilizzo delegation Invocazione di un metodo è propagata ai livelli superiori
dell’albero dell’ereditarietà
49Riccardo Cardin
function AbsProperty(){
this.build = function() {
var result = this.doSomething();
return "The decoration I did: " + result;
};
}
OpenButton.prototype = new AbsProperty();
function OpenButton () {
this.doSomething = function() { return "open button"; };
}
SeeButton.prototype = new AbsProperty();
function SeeButton () {
this. doSomething = function() { return "see button"; };
}
var button = new SeeButton(); button.build();
Risale l’albero dei
prototipi
Ricerca nel contesto
del metodo
Ingegneria del software mod. A
TEMPLATE METHOD
Implementazione
Le operazioni primitive dovrebbero essere membri protetti
Il template method non dovrebbe essere ridefinito Java: dichiarazione “final”
Minimizzare il numero di operazioni primitive … resta poco nel template method …
Definire una naming convention per i nomi delle operazioni di cui effettuare override
50Riccardo Cardin
Ingegneria del software mod. A
RIFERIMENTI
Design Patterns, Elements of Reusable Object Oriented Software, GoF, 1995, Addison-Wesley
Design Patterns http://sourcemaking.com/design_patterns
Java DP
http://www.javacamp.org/designPattern/
Deprecating the Observer Pattern http://lampwww.epfl.ch/~imaier/pub/DeprecatingObserversTR2010.pdf
Ruminations of a Programmer http://debasishg.blogspot.it/2009/01/subsuming-template-method-pattern.html
51Riccardo Cardin