Lezione 25: Design
    Pattern Comportamentali
         Corso di Ingegneria del Software
       Laurea Magistrale in Ing. Informatica
         Università degli Studi di Salerno



1
Outline


    ✦ Design Pattern Comportamentali
     •   Observer (continuazione)

     •   State

     •   Strategy

     •   Visitor




2
Design Pattern Comportamentali




3
Observer


    ✦ Conseguenze
     •   il Subject è disaccoppiato dagli oggetti che
         dipendono da esso (maggiore riusabilità e
         testabilità)
     •   comunicazione “broadcast”: il Subject non sa
         quanti oggetti dipendono da esso




4
Observer

    ✦ Note
     •   tutti gli Observer sono informati di tutte le
         variazioni dello stato del Subject; in alcuni casi
         questo può essere inefficiente
         ‣   una variante del pattern prevede che i possibili
             cambiamenti di stato siano divisi in categorie (“Topic”), e
             ciascun Observer specifica all’atto della registrazione quali
             sono i topic a cui è interessato




5
Observer

    ✦ Observer vs Chain of Responsibility
     •   i due pattern soddisfano un’esigenza simile, però
         ‣   nella Chain of Responibility si assume che uno solo degli
             handler gestisca effettivamente la richiesta; inoltre c’è una
             priorità tra gli handler: ciascun handler ha la possibilità di
             “filtrare” le richieste che arrivano agli handler successivi
         ‣   gli Observer invece sono tutti allo stesso livello, e
             tipicamente tutti gli observer rispondono in qualche modo
             a ciascun cambiamento (almeno per i Topic a cui sono
             registrati)




6
State

    ✦ Il problema
     •   un oggetto (Context) può trovarsi in più “stati”
         diversi, e il comportamento di alcune operazioni
         deve dipendere dallo stato in cui l’oggetto si trova
     •   si vuole evitare che la dipendenza del
         comportamento dallo stato sia “cablata”
         all’interno dei metodi dell’oggetto perché ciò
         renderebbe difficile cambiare/estendere l’insieme
         degli stati



7
State
    ✦ Esempio del problema
     •   un oggetto che rappresenta un file può essere in
         uno dei seguenti stati:
         ‣   chiuso
         ‣   aperto per operazioni di lettura
         ‣   aperto per operazioni di scrittura
         ‣   aperto per operazioni di lettura e scrittura

     •   le operazioni read e write, a seconda dello stato,
         svolgono la loro funzione oppure lanciano
         un’eccezione


8
State
    ✦ Esempio del problema
     •   in un programma di disegno l’utente può
         selezionare diversi strumenti
         ‣   matita
         ‣   gomma
         ‣   pennello
         ‣   disegno di linee
         ‣   ecc.

     •   il programma deve rispondere agli eventi del
         mouse in modo diverso a seconda dello strumento
         selezionato


9
State
     ✦ Soluzione
      •   lo stato del Context viene trasformato in un
          oggetto, che implementa un’interfaccia State con
          le operazioni che devono essere eseguite
          diversamente per ogni stato
      •   per ogni possibile stato si definisce una
          sottoclasse concreta di State
      •   il Context mantiene un riferimento all’oggetto che
          rappresenta lo stato corrente; per cambiare stato
          viene cambiato questo riferimento
      •   il Context delega allo stato corrente le operazioni
          che sono dipendenti dallo stato
10
State
     ✦ Esempio di struttura




11
State
       ✦ Esempio di soluzione
     import java.awt.*;

     public abstract class Tool {
     	 public void mouseDown(Graphics g, int x, int y) {
     	 	
     	 }
     	
     	 public void dragTo(Graphics g, int x, int y) {
     	 	
     	 }
     	
     	 public void mouseUp(Graphics g, int x, int y) {
     	 	
     	 }
     }

12
State
       ✦ Esempio di soluzione (continua)

     import java.awt.Graphics;

     public class LineTool extends Tool {
     	 private int prevX, prevY;
     	 public void mouseDown(Graphics g, int x, int y) {
     	 	 prevX = x;
     	 	 prevY = y;
     	 }
     	
     	 public void mouseUp(Graphics g, int x, int y) {
     	 	 g.drawLine(prevX, prevY, x, y);
     	 }
     }



13
State
        ✦ Esempio di soluzione (continua)
     import java.awt.Graphics;

     public class FreehandTool extends Tool {
     	 private int prevX, prevY;
     	
     	 public void mouseDown(Graphics g, int x, int y) {
     	 	 prevX = x;
     	 	 prevY = y;
     	 }
     	
     	 public void dragTo(Graphics g, int x, int y) {
     	 	 g.drawLine(prevX, prevY, x, y);
     	 	 prevX = x;
     	 	 prevY = y;
     	 }
     	
     	 public void mouseUp(Graphics g, int x, int y) {
     	 	 g.drawLine(prevX, prevY, x, y);
     	 }
     }

14
State
       ✦ Esempio di soluzione (continua)
     // . . .
     public class Doodle extends Canvas {
     	 private Tool selectedTool;
     	 public Doodle() {
                // . . .
     	 	 addMouseListener(new MouseAdapter() {
     	 	 	 public void mousePressed(MouseEvent evt) {
     	 	 	 	 selectedTool.mouseDown(getGraphics(), evt.getX(), evt.getY());
     	 	 	 }
                     // . . .
     	 	 });
               // . . .
          }
          // . . .
     	 public void setTool(Tool t) {
     	 	 selectedTool=t;
     	 }
          // . . .
     }


15
State

     ✦ Conseguenze
      •   la dipendenza dallo stato non è distribuita nel
          codice di diversi metodi del context, ma è raccolta
          nei metodi delle implementazioni concrete di
          State
      •   è semplice modificare il comportamento di uno
          specifico stato, oppure aggiungere al sistema
          nuovi stati inizialmente non previsti




16
Strategy

     ✦ Il problema
      •   spesso in un determinato contesto è necessario
          effettuare un’operazione (o un insieme di
          operazioni collegate) che può avere
          implementazioni diverse
      •   si vuole rendere il contesto indipendente da una
          particolare implementazione dell’operazione




17
Strategy
     ✦ Esempio del problema
      •   in un algoritmo di ordinamento basato su
          confronti è necessario comparare due oggetti
      •   la comparazione dipende dal tipo di oggetti da
          ordinare, ma anche per un singolo tipo di oggetti
          sono possibili diversi criteri di ordinamento, che
          corrispondono a diverse implementazioni
          dell’operazione di comparazione
      •   si vuole rendere l’algoritmo di ordinamento
          indipendente dal modo in cui viene effettuata la
          comparazione


18
Strategy

     ✦ Soluzione
      •   si definisce una interfaccia Strategy che contiene
          le operazioni di cui si vuole nascondere
          l’implementazione
      •   per ogni implementazione si definisce una
          sottoclasse concreta di Strategy
      •   l’oggetto che rappresenta il contesto (Context)
          riceve un riferimento a un’istanza di una
          sottoclasse concreta di Strategy



19
Strategy
     ✦ Esempio di struttura




20
Strategy
        ✦ Esempio di soluzione
           •    L’interfaccia Comparator nella libreria Java

     package java.util;

     public interface Comparator {
     	 // Confronta due oggetti
        // restituisce un valore <0, =0 o >0
        // a seconda che sia x<y, x=y, x>y
     	 int compare(Object x, Object y);
     	
        // verifica se un altro oggetto è uguale
        // a questo Comparator
     	 boolean equals(Object other);
     }




21
Strategy
        ✦ Esempio di soluzione (continua)
           •   Gli algoritmi di ordinamento nella libreria Java
               ricevono come parametro un Comparator


     public class Collections {
     	 // Ordina una lista
     	 public static List sort(List list, Comparator order) {
            // . . .
     	




22
Strategy

     ✦ Conseguenze
      •   è possibile realizzare in modo semplice famiglie di
          algoritmi simili che differiscono per
          l’implementazione di alcune operazioni
      •   il contesto può cambiare l’implementazione delle
          operazioni anche a run time, scegliendo un
          diverso oggetto Strategy




23
Strategy
     ✦ Template Method vs Strategy
      •   i due pattern risolvono lo stesso problema
      •   differenze:
          ‣   con Template Method non è necessario creare più oggetti
          ‣   con Strategy non c’è un’esplosione combinatoria di
              sottoclassi se il contesto ha più operazioni che devono
              essere incapsulate indipendentemente
          ‣   con Strategy l’implementazione delle operazioni
              incapsulate può essere effettuata a run time
          ‣   una stessa Strategy può essere utilizzata in contesti diversi




24
Strategy
      ✦ Esempio di implementazione
         •   Rivediamo l’esempio delle operazioni di
             accumulazione usando il pattern Strategy invece
             di Template Method
         •   per cominciare, definiamo l’interfaccia Strategy

     public interface AccumulationStrategy {
     	 int initialValue();
     	 int combine(int currentValue, int element);
     }




25
Strategy
       ✦ Esempio di implementazione (continua)
         •   definiamo ora la classe Accumulator
     public class Accumulator {
     	 private AccumulationStrategy strategy;
     	
     	 public Accumulator(AccumulationStrategy strategy) {
     	 	 this.strategy=strategy;
     	 }
     	
     	 public int compute(int a[], int n) {
     	 	 int value=strategy.initialValue();
     	 	 int i;
     	 	 for(i=0; i<n; i++)
     	 	 	 value=strategy.combine(value, a[i]);
     	 	 return value;
     	 }
     }
26
Strategy
       ✦ Esempio di implementazione (continua)
          •   definiamo ora le strategie concrete


     public class SumStrategy implements AccumulationStrategy {
     	 public int initialValue() {
     	 	 return 0;
     	 }
     	
     	 public int combine(int currentValue, int element) {
     	 	 return currentValue+element;
     	 }
     }




27
Strategy
       ✦ Esempio di implementazione (continua)
          •   definiamo ora le strategie concrete


     public class ProductStrategy implements AccumulationStrategy {
     	 public int initialValue() {
     	 	 return 1;
     	 }
     	
     	 public int combine(int currentValue, int element) {
     	 	 return currentValue*element;
     	 }
     }




28
Strategy
        ✦ Esempio di implementazione (continua)
           •   definiamo ora le strategie concrete
     public class CountPositiveStrategy implements AccumulationStrategy
     {
     	 public int initialValue() {
     	 	 return 0;
     	 }
     	
     	 public int combine(int currentValue, int element) {
     	 	 if (element>0)
     	 	 	 return currentValue+1;
     	 	 else
     	 	 	 return currentValue;
     	 }
     }


29
Strategy
        ✦ Esempio di implementazione (continua)
          •   esempio di uso di Accumulator:




     	 	 AccumulationStrategy strategy=new SumStrategy();
     	 	 Accumulator acc=new Accumulator(strategy);
     	 	 int sum=acc.compute(a,n);




30
Strategy
     ✦ State vs Strategy
      •   i due pattern sono molto simili (da un punto di
          vista implementativo sono identici)
      •   la differenza è nella finalità:
          ‣   Strategy serve a parametrizzare un algoritmo, State serve
              a semplificare l’implementazione di un comportamento
              complesso
          ‣   Una Strategy generalmente non cambia durante l’esistenza
              del Context (anche se è possibile farlo); uno State invece
              quasi sempre cambia durante l’esecuzione
          ‣   Di solito il Context conosce tutti i possibili State che sono
              applicabili (e gestisce il passaggio da uno State a un altro);
              il Context invece non conosce l’insieme delle possibili
              Strategy che potrà ricevere
31
Visitor
     ✦ Il problema
      •   in alcuni casi abbiamo una gerarchia di classi in
          cui la gerarchia è stabile (non capita l’esigenza di
          aggiungere nuove sottoclassi) ma l’insieme di
          operazioni che devono essere effettuate in tutte le
          classi è variabile (capita frequentemente di dover
          aggiungere alla classe base nuove operazioni che
          devono avere un’implementazione diversa in ogni
          sottoclasse)
      •   i meccanismi della programmazione orientata agli
          oggetti sono pensati per semplificare il caso
          contrario: operazioni stabili, e insieme delle classi
          variabile
32
Visitor
     ✦ Esempio del problema
      •   il nostro software gestisce il portale di una
          community di utenti che possono appartenere alle
          seguenti tre categorie:
          ‣   utente anonimo (non registrato)
          ‣   utente normale (registrato con iscrizione gratuita)
          ‣   utente “deluxe” (registrato con iscrizione a pagamento)

      •   il portale definisce una serie di operazioni il cui
          funzionamento è diverso a seconda della
          categoria di utente
      •   l’elenco delle operazioni disponibili cambia molto
          frequentemente
33
Visitor

     ✦ Esempio del problema (continua)
      •   Ad esempio, l’operazione “Invia un messaggio”
          può avere come comportamento:
          ‣   una segnalazione di errore per gli utenti anonimi
          ‣   l’invio condizionato alla verifica del numero massimo di
              messaggi inviabili in un giorno per gli utenti regolari
          ‣   l’invio incondizionato per gli utenti deluxe




34
Visitor
     ✦ Nota
         •     Un problema di questo tipo potrebbe essere
               risolto usando dei metodi con un if a cascata che
               esamina il tipo dell’oggetto:
              if (obj instanceof AnonymousUser)
     	   	       // ...
     	   	    else if (obj instanceof RegularUser)
     	   	    	 // ...
     	   	    else if (obj instanceof DeluxeUser)
     	   	    	 // ...
     	   	    else
     	   	    	 throw new RuntimeException("Unvalid class!");


             • in questo modo però il codice è meno chiaro, e c’è
              una violazione del principio DRY

35
Visitor
     ✦ Soluzione
        ‣ si definisce una interfaccia/classe astratta Visitor, con un
              metodo distinto per ogni classe concreta della gerarchia
          ‣   per ogni operazione da effettuare sugli oggetti (“elementi”)
              della gerarchia, si definisce una sottoclasse concreta di
              Visitor i cui metodi implementano il tipo di operazione da
              effettuare su ciascun tipo di elemento
          ‣   nella classe base della gerarchia si definisce un metodo
              astratto “accept” che riceve come parametro un Visitor
          ‣   le classi concrete della gerarchia implementano il metodo
              accept richiamando il metodo del Visitor che corrisponde al
              tipo di elemento in questione, a cui viene passato il
              riferimento all’elemento corrente (this)


36
Visitor
     ✦ Esempio di struttura




37
Visitor
       ✦ Esempio di soluzione

     public abstract class User {
     	 public String getIpAddress() {
     	 	 return "10.0.77.1";
     	 }
     	
     	 public abstract void accept(UserVisitor visitor);
     }




38
Visitor
       ✦ Esempio di soluzione (continua)

     public   interface UserVisitor {
     	 void   visitAnonymous(AnonymousUser user);
     	 void   visitRegular(RegularUser user);
     	 void   visitDeluxe(DeluxeUser user);
     }




39
Visitor
       ✦ Esempio di soluzione (continua)

     public class AnonymousUser extends User {
     	 public void accept(UserVisitor visitor) {
     	 	 visitor.visitAnonymous(this);
     	 }
     }




40
Visitor
       ✦ Esempio di soluzione (continua)
     public abstract class NamedUser extends User {
     	 private String name;
     	 public NamedUser(String name) {
     	 	 this.name = name;
     	 }
     	
     	 public String getName() {
     	 	 return name;
     	 }
     }




41
Visitor
        ✦ Esempio di soluzione (continua)
     public class RegularUser extends NamedUser {
     	 public static final int DAILY_CREDITS=100;
     	 private int credits;
     	 public RegularUser(String name) {
     	 	 super(name);
     	 	 credits=DAILY_CREDITS;
     	 }
     	 public void accept(UserVisitor visitor) {
     	 	 visitor.visitRegular(this);
     	 }
     	 public int getCredits() {
     	 	 return credits;
     	 }
     	 public void consumeCredits(int amount) {
     	 	 credits -= amount;
     	 }
     	 public void restoreCredits() {
     	 	 credits=DAILY_CREDITS;
     	 }
     }


42
Visitor
       ✦ Esempio di soluzione (continua)
     public class DeluxeUser extends NamedUser {
     	 private String creditCard;
     	 public DeluxeUser(String name, String creditCard) {
     	 	 super(name);
     	 	 this.creditCard=creditCard;
     	 }
     	 public void accept(UserVisitor visitor) {
     	 	 visitor.visitDeluxe(this);
     	 }
     	 public void pay(double amount) {
     	 	 System.out.println("User "+getName()+" has paid "+amount+
     	 	 	 	 " euros with card n. "+creditCard);
     	 }
     }


43
Visitor
     ✦ Esempio di soluzione (continua)

 public class SendMessageVisitor implements UserVisitor {
 	 public static final int MESSAGE_CREDITS=3;
 	 private String receiver, body;
 	 public SendMessageVisitor(String receiver, String body) {
 	 	 this.receiver=receiver;
 	 	 this.body=body;
 	 }
 	 public void visitAnonymous(AnonymousUser user) {
 	 	 System.out.print(user.getIpAddress());
 	 	 System.out.println(", non sei autorizzato a mandare messaggi!");
 	 }
    // continua ...




44
Visitor
         ✦ Esempio di soluzione (continua)
         // ... continua
     	   public void visitRegular(RegularUser user) {
     	   	 if (user.getCredits()>=MESSAGE_CREDITS) {
     	   	 	 System.out.print("Messaggio inviato da "+user.getName());
     	   	 	 System.out.println(" a "+receiver+": "+body);
     	   	 	 user.consumeCredits(MESSAGE_CREDITS);
     	   	 } else {
     	   	 	 System.out.print(user.getName());
     	   	 	 System.out.println(", hai esaurito i crediti a tua disposizione.");
     	   	 }
     	   }
     	   public void visitDeluxe(DeluxeUser user) {
     	   	 System.out.println("Esimio commendator "+user.getName()+",");
     	   	 System.out.println(" il suo messaggio: "+body);
     	   	 System.out.println(+receiver);
     	   	 System.out.println("Le porgiamo umilmente i nostri saluti.");
     	   }
     }



45
Visitor
         ✦ Esempio di soluzione (continua)


             // ...
     	   	   UserVisitor send=new SendMessageVisitor("Pippo", "ciao!");
     	   	   User a=new AnonymousUser();
     	   	   User b=new RegularUser("Paperino");
     	   	   User c=new DeluxeUser("Gastone", "PAP131313");
     	   	   a.accept(send);
     	   	   b.accept(send);
     	   	   c.accept(send);
             // ...




46
Visitor

     ✦ Conseguenze
      •   è semplice aggiungere nuove operazioni che
          abbiano un effetto diverso su ciascun tipo di
          elemento
      •   il codice delle operazioni non contiene “if” a
          cascata che controllano esplicitamente il tipo
          dell’oggetto
      •   PROBLEMA: è difficile aggiungere nuovi tipi di
          elemento (occorre cambiare tutti i Visitor)



47
Visitor
     ✦ Nota
      •   in un certo senso il pattern Visitor serve ad
          aggirare una limitazione del polimorfismo in Java
          (e nella maggior parte dei linguaggi OO):
          ‣   la scelta polimorfica del metodo da eseguire può dipendere
              dal tipo di un solo oggetto, il ricevente (si parla di single
              dispatch); invece negli esempi di applicabilità del pattern
              Visitor si vuole fare in modo che il metodo eseguito
              dipenda da DUE oggetti: l’elemento e l’operazione (double
              dispatch)

      •   in alcuni linguaggi di programmazione (es.
          Common Lisp, Dylan, Groovy, Perl 6) il multiple
          dispatch è supportato direttamente dal
          linguaggio, e non è quindi necessario questo
          pattern
48

More Related Content

PDF
Lezione 6a: Design Pattern Strutturali
PDF
Lezione 5: Design Pattern Creazionali
PDF
Lezione 2: I thread
PDF
Lezione 7: Design Pattern Comportamentali
PDF
Lezione 6b: Design Pattern Strutturali
PDF
Lezione 8: Design Pattern Comportamentali
PDF
Lezione 3: Sviluppo in Extreme Programming
PDF
Lezione 4: I tool Ant e Subversion
Lezione 6a: Design Pattern Strutturali
Lezione 5: Design Pattern Creazionali
Lezione 2: I thread
Lezione 7: Design Pattern Comportamentali
Lezione 6b: Design Pattern Strutturali
Lezione 8: Design Pattern Comportamentali
Lezione 3: Sviluppo in Extreme Programming
Lezione 4: I tool Ant e Subversion

What's hot (18)

PDF
Lezione 11: Accesso ai RESTful Web Services in Java
PDF
Lezione 2: Pianificazione in Extreme Programming
ODP
Design Pattern
PDF
Lezione 10: Web Service in Java (2)
PPT
PDF
Corso Java 2 - AVANZATO
PDF
Lezione 9: Web Service in Java
PDF
Java OCA teoria 1
PDF
Corso Javascript
PDF
Corso progettazione
PDF
Non solo Django: MVC orientato agli oggetti con Plone e Zope Toolkit
PDF
Design pattern template method
PDF
Java OCA teoria 4
PDF
Closure Visto Da Vicino
PDF
Lezione design patterns 2011 (Peron)
PPTX
Portlet JSR168/286
PDF
Introduzione alla programmazione Android - Android@tulug lezione 4
PDF
Programmazione funzionale e Stream in Java
Lezione 11: Accesso ai RESTful Web Services in Java
Lezione 2: Pianificazione in Extreme Programming
Design Pattern
Lezione 10: Web Service in Java (2)
Corso Java 2 - AVANZATO
Lezione 9: Web Service in Java
Java OCA teoria 1
Corso Javascript
Corso progettazione
Non solo Django: MVC orientato agli oggetti con Plone e Zope Toolkit
Design pattern template method
Java OCA teoria 4
Closure Visto Da Vicino
Lezione design patterns 2011 (Peron)
Portlet JSR168/286
Introduzione alla programmazione Android - Android@tulug lezione 4
Programmazione funzionale e Stream in Java
Ad

Similar to Lezione 9: Design Pattern Comportamentali (20)

PPTX
Il web 2.0
PDF
pattern
PDF
Approccio Pratico al Domain Driven Design
PPTX
C#, imparare a programmare e sopravvivere
PDF
Lezione 13 - Strategy
PPTX
Silverlight m v-vm @ DotNetteria
PPTX
Inversion of Control @ CD2008
PDF
Corso Unified Modeling Language (UML)
PDF
Waterfall Software Development Life Cycle
PDF
La gestione degli eventi e tecniche implementative
PDF
Lezione 03 - Interface
PDF
AntiPatterns: i vizi del programmatore
PDF
Programmazione in C (corso 12BHD Informatica)
PPTX
Lo sai che si può fare DDD in Javascript grazie a Typescript? Visual Studio e...
PDF
Modellazione UML per il WEB: Approccio di Conallen
PDF
Flow: viaggio nel futuro con un caso realizzato
PDF
OOP... Object Whaaat?
PPT
Riuso Object Oriented
PDF
Corso Object Oriented Analysis and Design
PDF
AreaMVC: un'architettura software basata sulla semplicità
Il web 2.0
pattern
Approccio Pratico al Domain Driven Design
C#, imparare a programmare e sopravvivere
Lezione 13 - Strategy
Silverlight m v-vm @ DotNetteria
Inversion of Control @ CD2008
Corso Unified Modeling Language (UML)
Waterfall Software Development Life Cycle
La gestione degli eventi e tecniche implementative
Lezione 03 - Interface
AntiPatterns: i vizi del programmatore
Programmazione in C (corso 12BHD Informatica)
Lo sai che si può fare DDD in Javascript grazie a Typescript? Visual Studio e...
Modellazione UML per il WEB: Approccio di Conallen
Flow: viaggio nel futuro con un caso realizzato
OOP... Object Whaaat?
Riuso Object Oriented
Corso Object Oriented Analysis and Design
AreaMVC: un'architettura software basata sulla semplicità
Ad

More from Andrea Della Corte (11)

PDF
Lezione 1: I metodi agili
PDF
Lezione 5: Socket SSL/ TLS
PDF
Lezione 8: Introduzione ai Web Service
PDF
Lezione 7: Remote Method Invocation e SSL
PDF
Lezione 6: Remote Method Invocation
PDF
Lezione12: Autenticazione e gestione delle sessioni in REST
PDF
Lezione 1: I/O in Java
PDF
Lezione 3: Connessioni TCP
PDF
Lezione 4: Comunicazione con UDP
PPT
Tutorial Matlab 2009
PPT
Introduzione ai CRM
Lezione 1: I metodi agili
Lezione 5: Socket SSL/ TLS
Lezione 8: Introduzione ai Web Service
Lezione 7: Remote Method Invocation e SSL
Lezione 6: Remote Method Invocation
Lezione12: Autenticazione e gestione delle sessioni in REST
Lezione 1: I/O in Java
Lezione 3: Connessioni TCP
Lezione 4: Comunicazione con UDP
Tutorial Matlab 2009
Introduzione ai CRM

Recently uploaded (12)

PDF
Presentazione di Chimica sui Coloranti Alimentari
PDF
NGÂN HÀNG CÂU HỎI TÁCH CHỌN LỌC THEO CHUYÊN ĐỀ TỪ ĐỀ THI THỬ TN THPT 2025 TIẾ...
PPTX
Sant'Agostino, vescovo di Ippona, dottore della Chiesa 354-430 d.C..pptx
PPTX
Santa Rosa da Lima, Vergine, Penitente, Terziaria Domenicana 1586-1617.pptx
PPTX
San Giuseppe Calasanzio, sacerdote cattolico, educatore 1557–1648.pptx
PDF
PRESENTAZIONE PROGETTO CCCI IN ITALIANO .pdf
PDF
Presentazione su educazione finanziaria e gestione della liquidità
PDF
NGÂN HÀNG CÂU HỎI TÁCH CHỌN LỌC THEO CHUYÊN ĐỀ TỪ ĐỀ THI THỬ TN THPT 2025 TIẾ...
PDF
NGÂN HÀNG CÂU HỎI TÁCH CHỌN LỌC THEO CHUYÊN ĐỀ TỪ ĐỀ THI THỬ TN THPT 2025 TIẾ...
PDF
Critico_o_creativo_Approcci_al_testo_let.pdf
PDF
"DIXIMUS: quello di cui noi parliamo" - edizione n.5
PDF
Libro per insegnare di Balboni: Lingue_e_linguaggi.pdf
Presentazione di Chimica sui Coloranti Alimentari
NGÂN HÀNG CÂU HỎI TÁCH CHỌN LỌC THEO CHUYÊN ĐỀ TỪ ĐỀ THI THỬ TN THPT 2025 TIẾ...
Sant'Agostino, vescovo di Ippona, dottore della Chiesa 354-430 d.C..pptx
Santa Rosa da Lima, Vergine, Penitente, Terziaria Domenicana 1586-1617.pptx
San Giuseppe Calasanzio, sacerdote cattolico, educatore 1557–1648.pptx
PRESENTAZIONE PROGETTO CCCI IN ITALIANO .pdf
Presentazione su educazione finanziaria e gestione della liquidità
NGÂN HÀNG CÂU HỎI TÁCH CHỌN LỌC THEO CHUYÊN ĐỀ TỪ ĐỀ THI THỬ TN THPT 2025 TIẾ...
NGÂN HÀNG CÂU HỎI TÁCH CHỌN LỌC THEO CHUYÊN ĐỀ TỪ ĐỀ THI THỬ TN THPT 2025 TIẾ...
Critico_o_creativo_Approcci_al_testo_let.pdf
"DIXIMUS: quello di cui noi parliamo" - edizione n.5
Libro per insegnare di Balboni: Lingue_e_linguaggi.pdf

Lezione 9: Design Pattern Comportamentali

  • 1. Lezione 25: Design Pattern Comportamentali Corso di Ingegneria del Software Laurea Magistrale in Ing. Informatica Università degli Studi di Salerno 1
  • 2. Outline ✦ Design Pattern Comportamentali • Observer (continuazione) • State • Strategy • Visitor 2
  • 4. Observer ✦ Conseguenze • il Subject è disaccoppiato dagli oggetti che dipendono da esso (maggiore riusabilità e testabilità) • comunicazione “broadcast”: il Subject non sa quanti oggetti dipendono da esso 4
  • 5. Observer ✦ Note • tutti gli Observer sono informati di tutte le variazioni dello stato del Subject; in alcuni casi questo può essere inefficiente ‣ una variante del pattern prevede che i possibili cambiamenti di stato siano divisi in categorie (“Topic”), e ciascun Observer specifica all’atto della registrazione quali sono i topic a cui è interessato 5
  • 6. Observer ✦ Observer vs Chain of Responsibility • i due pattern soddisfano un’esigenza simile, però ‣ nella Chain of Responibility si assume che uno solo degli handler gestisca effettivamente la richiesta; inoltre c’è una priorità tra gli handler: ciascun handler ha la possibilità di “filtrare” le richieste che arrivano agli handler successivi ‣ gli Observer invece sono tutti allo stesso livello, e tipicamente tutti gli observer rispondono in qualche modo a ciascun cambiamento (almeno per i Topic a cui sono registrati) 6
  • 7. State ✦ Il problema • un oggetto (Context) può trovarsi in più “stati” diversi, e il comportamento di alcune operazioni deve dipendere dallo stato in cui l’oggetto si trova • si vuole evitare che la dipendenza del comportamento dallo stato sia “cablata” all’interno dei metodi dell’oggetto perché ciò renderebbe difficile cambiare/estendere l’insieme degli stati 7
  • 8. State ✦ Esempio del problema • un oggetto che rappresenta un file può essere in uno dei seguenti stati: ‣ chiuso ‣ aperto per operazioni di lettura ‣ aperto per operazioni di scrittura ‣ aperto per operazioni di lettura e scrittura • le operazioni read e write, a seconda dello stato, svolgono la loro funzione oppure lanciano un’eccezione 8
  • 9. State ✦ Esempio del problema • in un programma di disegno l’utente può selezionare diversi strumenti ‣ matita ‣ gomma ‣ pennello ‣ disegno di linee ‣ ecc. • il programma deve rispondere agli eventi del mouse in modo diverso a seconda dello strumento selezionato 9
  • 10. State ✦ Soluzione • lo stato del Context viene trasformato in un oggetto, che implementa un’interfaccia State con le operazioni che devono essere eseguite diversamente per ogni stato • per ogni possibile stato si definisce una sottoclasse concreta di State • il Context mantiene un riferimento all’oggetto che rappresenta lo stato corrente; per cambiare stato viene cambiato questo riferimento • il Context delega allo stato corrente le operazioni che sono dipendenti dallo stato 10
  • 11. State ✦ Esempio di struttura 11
  • 12. State ✦ Esempio di soluzione import java.awt.*; public abstract class Tool { public void mouseDown(Graphics g, int x, int y) { } public void dragTo(Graphics g, int x, int y) { } public void mouseUp(Graphics g, int x, int y) { } } 12
  • 13. State ✦ Esempio di soluzione (continua) import java.awt.Graphics; public class LineTool extends Tool { private int prevX, prevY; public void mouseDown(Graphics g, int x, int y) { prevX = x; prevY = y; } public void mouseUp(Graphics g, int x, int y) { g.drawLine(prevX, prevY, x, y); } } 13
  • 14. State ✦ Esempio di soluzione (continua) import java.awt.Graphics; public class FreehandTool extends Tool { private int prevX, prevY; public void mouseDown(Graphics g, int x, int y) { prevX = x; prevY = y; } public void dragTo(Graphics g, int x, int y) { g.drawLine(prevX, prevY, x, y); prevX = x; prevY = y; } public void mouseUp(Graphics g, int x, int y) { g.drawLine(prevX, prevY, x, y); } } 14
  • 15. State ✦ Esempio di soluzione (continua) // . . . public class Doodle extends Canvas { private Tool selectedTool; public Doodle() { // . . . addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { selectedTool.mouseDown(getGraphics(), evt.getX(), evt.getY()); } // . . . }); // . . . } // . . . public void setTool(Tool t) { selectedTool=t; } // . . . } 15
  • 16. State ✦ Conseguenze • la dipendenza dallo stato non è distribuita nel codice di diversi metodi del context, ma è raccolta nei metodi delle implementazioni concrete di State • è semplice modificare il comportamento di uno specifico stato, oppure aggiungere al sistema nuovi stati inizialmente non previsti 16
  • 17. Strategy ✦ Il problema • spesso in un determinato contesto è necessario effettuare un’operazione (o un insieme di operazioni collegate) che può avere implementazioni diverse • si vuole rendere il contesto indipendente da una particolare implementazione dell’operazione 17
  • 18. Strategy ✦ Esempio del problema • in un algoritmo di ordinamento basato su confronti è necessario comparare due oggetti • la comparazione dipende dal tipo di oggetti da ordinare, ma anche per un singolo tipo di oggetti sono possibili diversi criteri di ordinamento, che corrispondono a diverse implementazioni dell’operazione di comparazione • si vuole rendere l’algoritmo di ordinamento indipendente dal modo in cui viene effettuata la comparazione 18
  • 19. Strategy ✦ Soluzione • si definisce una interfaccia Strategy che contiene le operazioni di cui si vuole nascondere l’implementazione • per ogni implementazione si definisce una sottoclasse concreta di Strategy • l’oggetto che rappresenta il contesto (Context) riceve un riferimento a un’istanza di una sottoclasse concreta di Strategy 19
  • 20. Strategy ✦ Esempio di struttura 20
  • 21. Strategy ✦ Esempio di soluzione • L’interfaccia Comparator nella libreria Java package java.util; public interface Comparator { // Confronta due oggetti // restituisce un valore <0, =0 o >0 // a seconda che sia x<y, x=y, x>y int compare(Object x, Object y); // verifica se un altro oggetto è uguale // a questo Comparator boolean equals(Object other); } 21
  • 22. Strategy ✦ Esempio di soluzione (continua) • Gli algoritmi di ordinamento nella libreria Java ricevono come parametro un Comparator public class Collections { // Ordina una lista public static List sort(List list, Comparator order) { // . . . 22
  • 23. Strategy ✦ Conseguenze • è possibile realizzare in modo semplice famiglie di algoritmi simili che differiscono per l’implementazione di alcune operazioni • il contesto può cambiare l’implementazione delle operazioni anche a run time, scegliendo un diverso oggetto Strategy 23
  • 24. Strategy ✦ Template Method vs Strategy • i due pattern risolvono lo stesso problema • differenze: ‣ con Template Method non è necessario creare più oggetti ‣ con Strategy non c’è un’esplosione combinatoria di sottoclassi se il contesto ha più operazioni che devono essere incapsulate indipendentemente ‣ con Strategy l’implementazione delle operazioni incapsulate può essere effettuata a run time ‣ una stessa Strategy può essere utilizzata in contesti diversi 24
  • 25. Strategy ✦ Esempio di implementazione • Rivediamo l’esempio delle operazioni di accumulazione usando il pattern Strategy invece di Template Method • per cominciare, definiamo l’interfaccia Strategy public interface AccumulationStrategy { int initialValue(); int combine(int currentValue, int element); } 25
  • 26. Strategy ✦ Esempio di implementazione (continua) • definiamo ora la classe Accumulator public class Accumulator { private AccumulationStrategy strategy; public Accumulator(AccumulationStrategy strategy) { this.strategy=strategy; } public int compute(int a[], int n) { int value=strategy.initialValue(); int i; for(i=0; i<n; i++) value=strategy.combine(value, a[i]); return value; } } 26
  • 27. Strategy ✦ Esempio di implementazione (continua) • definiamo ora le strategie concrete public class SumStrategy implements AccumulationStrategy { public int initialValue() { return 0; } public int combine(int currentValue, int element) { return currentValue+element; } } 27
  • 28. Strategy ✦ Esempio di implementazione (continua) • definiamo ora le strategie concrete public class ProductStrategy implements AccumulationStrategy { public int initialValue() { return 1; } public int combine(int currentValue, int element) { return currentValue*element; } } 28
  • 29. Strategy ✦ Esempio di implementazione (continua) • definiamo ora le strategie concrete public class CountPositiveStrategy implements AccumulationStrategy { public int initialValue() { return 0; } public int combine(int currentValue, int element) { if (element>0) return currentValue+1; else return currentValue; } } 29
  • 30. Strategy ✦ Esempio di implementazione (continua) • esempio di uso di Accumulator: AccumulationStrategy strategy=new SumStrategy(); Accumulator acc=new Accumulator(strategy); int sum=acc.compute(a,n); 30
  • 31. Strategy ✦ State vs Strategy • i due pattern sono molto simili (da un punto di vista implementativo sono identici) • la differenza è nella finalità: ‣ Strategy serve a parametrizzare un algoritmo, State serve a semplificare l’implementazione di un comportamento complesso ‣ Una Strategy generalmente non cambia durante l’esistenza del Context (anche se è possibile farlo); uno State invece quasi sempre cambia durante l’esecuzione ‣ Di solito il Context conosce tutti i possibili State che sono applicabili (e gestisce il passaggio da uno State a un altro); il Context invece non conosce l’insieme delle possibili Strategy che potrà ricevere 31
  • 32. Visitor ✦ Il problema • in alcuni casi abbiamo una gerarchia di classi in cui la gerarchia è stabile (non capita l’esigenza di aggiungere nuove sottoclassi) ma l’insieme di operazioni che devono essere effettuate in tutte le classi è variabile (capita frequentemente di dover aggiungere alla classe base nuove operazioni che devono avere un’implementazione diversa in ogni sottoclasse) • i meccanismi della programmazione orientata agli oggetti sono pensati per semplificare il caso contrario: operazioni stabili, e insieme delle classi variabile 32
  • 33. Visitor ✦ Esempio del problema • il nostro software gestisce il portale di una community di utenti che possono appartenere alle seguenti tre categorie: ‣ utente anonimo (non registrato) ‣ utente normale (registrato con iscrizione gratuita) ‣ utente “deluxe” (registrato con iscrizione a pagamento) • il portale definisce una serie di operazioni il cui funzionamento è diverso a seconda della categoria di utente • l’elenco delle operazioni disponibili cambia molto frequentemente 33
  • 34. Visitor ✦ Esempio del problema (continua) • Ad esempio, l’operazione “Invia un messaggio” può avere come comportamento: ‣ una segnalazione di errore per gli utenti anonimi ‣ l’invio condizionato alla verifica del numero massimo di messaggi inviabili in un giorno per gli utenti regolari ‣ l’invio incondizionato per gli utenti deluxe 34
  • 35. Visitor ✦ Nota • Un problema di questo tipo potrebbe essere risolto usando dei metodi con un if a cascata che esamina il tipo dell’oggetto: if (obj instanceof AnonymousUser) // ... else if (obj instanceof RegularUser) // ... else if (obj instanceof DeluxeUser) // ... else throw new RuntimeException("Unvalid class!"); • in questo modo però il codice è meno chiaro, e c’è una violazione del principio DRY 35
  • 36. Visitor ✦ Soluzione ‣ si definisce una interfaccia/classe astratta Visitor, con un metodo distinto per ogni classe concreta della gerarchia ‣ per ogni operazione da effettuare sugli oggetti (“elementi”) della gerarchia, si definisce una sottoclasse concreta di Visitor i cui metodi implementano il tipo di operazione da effettuare su ciascun tipo di elemento ‣ nella classe base della gerarchia si definisce un metodo astratto “accept” che riceve come parametro un Visitor ‣ le classi concrete della gerarchia implementano il metodo accept richiamando il metodo del Visitor che corrisponde al tipo di elemento in questione, a cui viene passato il riferimento all’elemento corrente (this) 36
  • 37. Visitor ✦ Esempio di struttura 37
  • 38. Visitor ✦ Esempio di soluzione public abstract class User { public String getIpAddress() { return "10.0.77.1"; } public abstract void accept(UserVisitor visitor); } 38
  • 39. Visitor ✦ Esempio di soluzione (continua) public interface UserVisitor { void visitAnonymous(AnonymousUser user); void visitRegular(RegularUser user); void visitDeluxe(DeluxeUser user); } 39
  • 40. Visitor ✦ Esempio di soluzione (continua) public class AnonymousUser extends User { public void accept(UserVisitor visitor) { visitor.visitAnonymous(this); } } 40
  • 41. Visitor ✦ Esempio di soluzione (continua) public abstract class NamedUser extends User { private String name; public NamedUser(String name) { this.name = name; } public String getName() { return name; } } 41
  • 42. Visitor ✦ Esempio di soluzione (continua) public class RegularUser extends NamedUser { public static final int DAILY_CREDITS=100; private int credits; public RegularUser(String name) { super(name); credits=DAILY_CREDITS; } public void accept(UserVisitor visitor) { visitor.visitRegular(this); } public int getCredits() { return credits; } public void consumeCredits(int amount) { credits -= amount; } public void restoreCredits() { credits=DAILY_CREDITS; } } 42
  • 43. Visitor ✦ Esempio di soluzione (continua) public class DeluxeUser extends NamedUser { private String creditCard; public DeluxeUser(String name, String creditCard) { super(name); this.creditCard=creditCard; } public void accept(UserVisitor visitor) { visitor.visitDeluxe(this); } public void pay(double amount) { System.out.println("User "+getName()+" has paid "+amount+ " euros with card n. "+creditCard); } } 43
  • 44. Visitor ✦ Esempio di soluzione (continua) public class SendMessageVisitor implements UserVisitor { public static final int MESSAGE_CREDITS=3; private String receiver, body; public SendMessageVisitor(String receiver, String body) { this.receiver=receiver; this.body=body; } public void visitAnonymous(AnonymousUser user) { System.out.print(user.getIpAddress()); System.out.println(", non sei autorizzato a mandare messaggi!"); } // continua ... 44
  • 45. Visitor ✦ Esempio di soluzione (continua) // ... continua public void visitRegular(RegularUser user) { if (user.getCredits()>=MESSAGE_CREDITS) { System.out.print("Messaggio inviato da "+user.getName()); System.out.println(" a "+receiver+": "+body); user.consumeCredits(MESSAGE_CREDITS); } else { System.out.print(user.getName()); System.out.println(", hai esaurito i crediti a tua disposizione."); } } public void visitDeluxe(DeluxeUser user) { System.out.println("Esimio commendator "+user.getName()+","); System.out.println(" il suo messaggio: "+body); System.out.println(+receiver); System.out.println("Le porgiamo umilmente i nostri saluti."); } } 45
  • 46. Visitor ✦ Esempio di soluzione (continua) // ... UserVisitor send=new SendMessageVisitor("Pippo", "ciao!"); User a=new AnonymousUser(); User b=new RegularUser("Paperino"); User c=new DeluxeUser("Gastone", "PAP131313"); a.accept(send); b.accept(send); c.accept(send); // ... 46
  • 47. Visitor ✦ Conseguenze • è semplice aggiungere nuove operazioni che abbiano un effetto diverso su ciascun tipo di elemento • il codice delle operazioni non contiene “if” a cascata che controllano esplicitamente il tipo dell’oggetto • PROBLEMA: è difficile aggiungere nuovi tipi di elemento (occorre cambiare tutti i Visitor) 47
  • 48. Visitor ✦ Nota • in un certo senso il pattern Visitor serve ad aggirare una limitazione del polimorfismo in Java (e nella maggior parte dei linguaggi OO): ‣ la scelta polimorfica del metodo da eseguire può dipendere dal tipo di un solo oggetto, il ricevente (si parla di single dispatch); invece negli esempi di applicabilità del pattern Visitor si vuole fare in modo che il metodo eseguito dipenda da DUE oggetti: l’elemento e l’operazione (double dispatch) • in alcuni linguaggi di programmazione (es. Common Lisp, Dylan, Groovy, Perl 6) il multiple dispatch è supportato direttamente dal linguaggio, e non è quindi necessario questo pattern 48