Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Lezione 8: Design Pattern Comportamentali

2,144 views

Published on

✦ Design Pattern Comportamentali
• Command
• Iterator
• Observer

Published in: Education, Technology
  • Be the first to comment

  • Be the first to like this

Lezione 8: Design Pattern Comportamentali

  1. 1. Lezione 24: Design Pattern Comportamentali Corso di Ingegneria del Software Laurea Magistrale in Ing. Informatica Università degli Studi di Salerno 1
  2. 2. Outline ✦ Design Pattern Comportamentali • Command • Iterator • Observer 2
  3. 3. Design Pattern Comportamentali 3
  4. 4. Command ✦ Il problema • spesso un sistema deve eseguire delle azioni che hanno per oggetto altre azioni del sistema ‣ es. il comando Undo che annulla un’azione precedente, o il comando Redo che riesegue un’azione precedente ‣ es. salvataggio di una sequenza di azioni come “macro” ‣ es. i comandi di personalizzazione della barra dei menù o delle toolbar, che aggiungono/rimuovono associazioni tra azioni da eseguire e icone/menù 4
  5. 5. Command ✦ Soluzione • si definisce una interfaccia/classe astratta Command, con metodi per eseguire (e se necessario, annullare, registrare ecc.) un comando • ogni azione è implementata con una classe concreta che implementa Command, e incapsula il codice per eseguire lo specifico comando e le informazioni di cui il comando ha bisogno 5
  6. 6. Command ✦ Esempio di struttura 6
  7. 7. Command ✦ Esempio di soluzione • Supponiamo di avere una classe Account che rappresenta un conto corrente, e vogliamo che nel nostro programma le operazioni di prelievo (withdraw) e versamento (deposit) siano “annullabili”, con il vincolo che l’annullamento può essere fatto solo in ordine cronologico inverso 7
  8. 8. Command ✦ Esempio di soluzione (continua) public class Account { private double balance; // Saldo del conto public Account(double initialBalance) { balance=initialBalance; } // Restituisce il saldo public double getBalance() { return balance; } // Esegue un versamento public void deposit(double amount) { balance += amount; } // Esegue un prelievo public void withdraw(double amount) { balance -= amount; } } 8
  9. 9. Command ✦ Esempio di soluzione (continua) public abstract class Command { protected Account account; protected Command(Account account) { this.account = account; } public abstract void perform(); public abstract void undo(); } 9
  10. 10. Command ✦ Esempio di soluzione (continua) public class DepositCommand extends Command { private double amount; public DepositCommand(Account account, double amount) { super(account); this.amount=amount; } public void perform() { account.deposit(amount); } public void undo() { account.withdraw(amount); } } 10
  11. 11. Command ✦ Esempio di soluzione (continua) public class WithdrawCommand extends Command { private double amount; public WithdrawCommand(Account account, double amount) { super(account); this.amount=amount; } public void perform() { account.withdraw(amount); } public void undo() { account.deposit(amount); } } 11
  12. 12. Command ✦ Esempio di soluzione (continua) import java.util.Stack; public class AccountManager { private Account account; private Stack<Command> commandHistory; public AccountManager(Account account) { this.account=account; commandHistory=new Stack<Command>(); } public double getBalance() { return account.getBalance(); } // continua ... 12
  13. 13. Command ✦ Esempio di soluzione (continua) // ... continua public void deposit(double amount) { Command cmd=new DepositCommand(account, amount); commandHistory.push(cmd); cmd.perform(); } public void withdraw(double amount) { Command cmd=new WithdrawCommand(account, amount); commandHistory.push(cmd); cmd.perform(); } public void undo() { Command last=commandHistory.pop(); last.undo(); } } 13
  14. 14. Command ✦ Conseguenze • la definizione delle azioni da eseguire e la loro esecuzione sono disaccoppiate • è possibile creare comandi composti, o comandi che manipolano altri comandi (es. Undo) • è possibile estendere facilmente l’insieme dei comandi • PROBLEMA: la definizione del singolo comando è più complessa rispetto alla semplice definizione di un metodo; il pattern è conveniente solo se il programma ha bisogno di realizzare comandi che lavorano su altri comandi 14
  15. 15. Iterator ✦ Altri nomi: Cursor ✦ Il problema • molte strutture dati rappresentano “aggregati” di oggetti (“collezioni”, “contenitori”) • i meccanismi di accesso più efficienti per una struttura dati possono essere estremamente inefficienti per un’altra ‣ es. l’accesso per indice è efficiente se la struttura dati è un array, e inefficiente se la struttura dati è una lista concatenata • si vuole consentire al client di un aggregato di accedere all’elenco degli oggetti contenuti senza dipendere dalla struttura dati effettivamente 15 utilizzata per implementare l’aggregato
  16. 16. Iterator ✦ Soluzione • si definisce un’interfaccia Iterator che rappresenta in maniera astratta una posizione all’interno dell’aggregato; l’iteratore fornisce metodi per verificare se ci sono altri elementi da esaminare, per accedere all’elemento che si trova in quella posizione e per passare alla posizione successiva • l’implementazione dell’aggregato è associata a un’implementazione concreta dell’iteratore, che il client può ottenere attraverso un Factory Method 16
  17. 17. Iterator ✦ Esempio di struttura 17
  18. 18. Iterator ✦ Esempio • gli iteratori per le collezioni nella libreria standard di Java ✦ Esempio • nella libreria JDBC, per accedere ai risultati di una query su un database si usano oggetti che implementano l’interfaccia ResultSet, che consente di esaminare in sequenza tutte le righe del risultato 18
  19. 19. Iterator ✦ Conseguenze • il client di una collezione di oggetti può accedere in modo efficiente ai contenuti della collezione senza dipendere dalla conoscenza della specifica struttura dati utilizzata ✦ Note • imponendo vincoli aggiuntivi sulla collezione è possibile definire più operazioni sugli iteratori ‣ esempio: iteratori bidirezionali ‣ esempio: inserimento/cancellazione dell’elemento corrente • in molti linguaggi, gli iteratori sono direttamente supportati dalla sintassi del linguaggio 19
  20. 20. Observer ✦ Noto anche come: Publish-Subscribe ✦ Il problema • spesso i cambiamenti nello stato di un oggetto (Subject) devono riflettersi su uno o più oggetti da esso dipendenti • si vuole disaccoppiare il Subject dagli oggetti dipendenti 20
  21. 21. Observer ✦ Esempio del problema • se decidiamo di separare le classi che gestiscono i dati del nostro sistema (“Model”) dalle classi che si occupano della visualizzazione (“View”), come facciamo ad aggiornare la visualizzazione quando i dati cambiano SENZA introdurre nel Model una dipendenza dall’interfaccia utente? ‣ idealmente le classi che si occupano della business logic dovrebbero essere riusabili con interfacce utente diverse (es. command line, GUI, web) ‣ di uno stesso dato l’utente può richiedere visualizzazioni diverse (es. spreadsheet e grafico) 21
  22. 22. Observer ✦ Soluzione • si definisce un’interfaccia Observer, con un metodo che viene richiamato ad ogni modifica dello stato del Subject • gli oggetti (che implementano Observer) che sono interessati a un determinato Subject devono essere registrati presso il Subject con un apposito metodo • il Subject provvede a richiamare il metodo di notifica per tutti gli Observer registrati ogni volta che cambia il proprio stato 22
  23. 23. Observer ✦ Esempio di struttura 23
  24. 24. Observer ✦ Esempio • A partire dalla versione 1.1 della libreria AWT, gli eventi sono gestiti usando questo pattern ‣ per ogni tipo di evento è definita un’interfaccia Listener, che ha il ruolo di Observer ‣ il Subject è il componente GUI che genera l’evento 24
  25. 25. Observer ✦ Esempio • la libreria standard Java mette a disposizione una classe (java.util.Observable) e un’interfaccia (java.util.Observer) per implementare semplicemente questo pattern ‣ il Subject estende Observable ‣ quando un metodo modifica lo stato del subject, deve chiamare il metodo setChanged per segnalare che c’è stato un cambiamento ‣ al termine di una serie di cambiamenti occorre chiamare il metodo notifyObservers per avvisare gli Observer ‣ ciascun Observer viene avvisato del cambiamento attraverso il metodo update 25
  26. 26. Observer ✦ Esempio • supponiamo di voler realizzare una classe AlertCondition che rappresenti la condizione di “allerta” del nostro sistema: ‣ la condizione può essere GREEN (“tutto normale”), YELLOW (“situazione di potenziale pericolo”) o RED (“emergenza”) • vogliamo fare in modo che i cambiamenti della condizione di allerta siano registrati su un file di log, e inoltre siano visualizzati graficamente e, in caso di condizione RED, anche auditivamente 26
  27. 27. Observer ✦ Esempio (continua) import java.util.Observable; public class AlertCondition extends Observable { public static final int GREEN=0, YELLOW=1, RED=2; private int condition; public AlertCondition() { condition=GREEN; } public int getCondition() { return condition; } public void setCondition(int newCondition) { if (newCondition!=RED && newCondition!=YELLOW && newCondition!=GREEN) throw new RuntimeException("Unvalid alert condition!"); if (newCondition != condition) { condition=newCondition; setChanged(); } notifyObservers(); } } 27
  28. 28. Observer ✦ Esempio (continua) import java.util.*; import java.io.*; import java.text.*; public class LogAlertObserver implements Observer { private PrintWriter out; public LogAlertObserver(String fileName) throws IOException { FileOutputStream fos=new FileOutputStream(fileName, true); OutputStreamWriter osw=new OutputStreamWriter(fos, "UTF-8"); out=new PrintWriter(osw); } public void update(Observable subject, Object arg) { AlertCondition alert=(AlertCondition)subject; DateFormat dfmt=DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG); String date=dfmt.format(new Date()); String state; switch (alert.getCondition()) { case AlertCondition.GREEN: state="GREEN"; break; case AlertCondition.YELLOW: state="YELLOW"; break; case AlertCondition.RED: state="RED"; break; default: state="UNKNOWN"; } out.println("["+date+"] the alert is: "+state); out.flush(); } } 28
  29. 29. Observer ✦ Esempio (continua) import java.awt.*; import java.awt.event.*; import java.util.*; public class GraphicAlertObserver extends Frame implements Observer { private Canvas canvas; public GraphicAlertObserver() { super("Alert status"); // ... continua ... setSize(400, 300); public void update(Observable subject, Object arg) { canvas=new Canvas(); AlertCondition alert=(AlertCondition)subject; canvas.setBackground(Color.GREEN); switch (alert.getCondition()) { add("Center", canvas); case AlertCondition.GREEN: setVisible(true); canvas.setBackground(Color.GREEN); } break; // ... continua ... case AlertCondition.YELLOW: canvas.setBackground(Color.YELLOW); break; case AlertCondition.RED: canvas.setBackground(Color.RED); break; default: canvas.setBackground(Color.GRAY); break; } canvas.repaint(); } 29 }
  30. 30. Observer ✦ Esempio (continua) import java.util.*; import java.applet.*; import java.net.*; public class SoundAlertObserver implements Observer { private AudioClip clip; public SoundAlertObserver(String audioClipName) { URL url=getClass().getResource(audioClipName); clip=Applet.newAudioClip(url); } public void update(Observable subject, Object arg) { AlertCondition alert=(AlertCondition)subject; if (alert.getCondition()==AlertCondition.RED) clip.loop(); else clip.stop(); } } 30
  31. 31. Observer ✦ Esempio (continua) import java.io.*; public class Main implements Runnable { public static void main(String args[]) throws IOException { new Main(); } private AlertCondition alert; public Main() throws IOException { alert=new AlertCondition(); alert.addObserver(new LogAlertObserver("alert.log")); alert.addObserver(new GraphicAlertObserver()); alert.addObserver(new SoundAlertObserver("alarm.wav")); Thread t=new Thread(this); t.start(); } // ... continua .... 31
  32. 32. Observer ✦ Esempio (continua) // ... continua .... public void run() { final int DELAY=3000; while (true) { try { alert.setCondition(AlertCondition.GREEN); Thread.sleep(DELAY); alert.setCondition(AlertCondition.YELLOW); Thread.sleep(DELAY); alert.setCondition(AlertCondition.RED); Thread.sleep(DELAY); } catch (InterruptedException exc) { } } } } 32

×