Beruflich Dokumente
Kultur Dokumente
Soluzione
Gli oggetti vengono creati con un metodo:
Il metodo pu stare nella classe che usa gli oggetti oppure in unaltra classe come
metodo static;
Il metodo pu essere abstract e quindi deve essere implementato in una sottoclasse.
Struttura
Creator: dichiara il Factory Method;
ConcreteCreator: implementa il
Factory Method al fine di ritornare
loggetto;
Product: interfaccia delloggetto da
creare;
ConcreteProduct: implementa
loggetto ed i metodi della sua
interfaccia.
Conseguenze
Esempi
Creazione di un iteratore
Iterator iter = MyCollection.iterator();
Soluzione
Si definisce linterfaccia AbstractFactory che ha i metodi per creare i diversi prodotti e una o
pi classi concrete che implementano linterfaccia creando una famiglia di prodotti.
La creazione della ConcreteFactory avviene a run-time e pu essere realizzata anche con un
Factory Method.
Struttura
AbstractFactory: interfaccia che contiene le firme dei metodi per creare i prodotti;
ConcreteFactory: implementazione dei metodi per creare i prodotti;
AbscractProduct: interfaccia che contiene le firme dei metodi relativi ai prodotti;
Product: implementazione dei metodi relativi ai prodotti.
Conseguenze
Nasconde le classi concrete, le quali sono istanziate solo dalle Factory e non
direttamente dal client;
Si pu sostituire facilmente una famiglia di prodotti con unaltra senza dover
modificare il client;
I prodotti devono essere della stessa famiglia dato che implementano lo stesso
AbstractProduct;
Svantaggio: oneroso aggiungere nuovi prodotti ad una famiglia in quanto questo
implica la modifica di tutte le ConcreteFactory.
Esempio
La libreria AWT deve poter creare per ogni componente un oggetto la cui implementazione
dipende dalla piattaforma utilizzata. Si risolve rendendo la classe java.awt.Toolkit una
AbstractFactory, per la quale viene creata una sottoclasse concreta con un Factory Method
Singleton (Object)
Problema
Vogliamo che una classe abbia ununica istanza, accessibile attraverso un unico punto di
accesso; pu essere necessario quando la classe contiene informazioni di stato che devono
essere condivise da pi parti del programma.
Soluzione
Si rende il costruttore della classe privato (non accessibile dallesterno); quindi si fornisce
un metodo static che restituisce lunica istanza della classe conservata in un campo static
privato.
Struttura
Conseguenze
Esempio
Nella libreria AWT la classe SystemTray un Singleton, dato che sul desktop ci pu essere
un solo system tray.
Implementazione
import java.util.*;
public class Cache {
static private Cache instance=null;
public static Cache getCache() {
if (instance==null)
instance=new Cache();
return instance;
}
private Map<String, String> map;
private Cache() {
map=new HashMap<String, String>();
}
public String get(String key) {
return map.get(key);
}
public void put(String key, String value) {
map.put(key, value);
Soluzione
Class
Si crea una classe Adapter che implementa
linterfaccia Target ed eredita
limplementazione della classe Adaptee; i
metodi di Adapter richiamano quelli di
Adaptee.
Object
Si crea una classe Adapter che implementa
linterfaccia Target e contiene un
riferimento ad un oggetto della classe
Adaptee; i metodi di Adapter richiamano
quelli di Adaptee.
Alternativa: la classe Adapter pu essere
realizzata come classe interna dellAdaptee;
cos lAdapter ha accesso anche alle
componenti private di Adaptee e non si
aggiungono nuove classi visibili allesterno.
Struttura
Class
Object
Conseguenze
Class
Se Target non uninterfaccia pura,
necessaria lereditariet multipla;
Un Adapter adatta un solo Adaptee,
pertanto se ci sono pi Adaptee
occorrono anche pi Adapter;
Viene creato solamente loggetto
Adapter che include al suo interno
sia Target sia Adaptee, pertanto c
un basso overhead a tempo di
esecuzione.
Object
LAdapter pu essere associato a pi
Adaptee;
LAdapter pu essere utilizzato per
oggetti della classe Adaptee e delle
sue classi derivate;
Si pu cambiare lAdaptee associato
a run-time;
Adapter e Adaptee rimangono 2
oggetti distinti (overhead di
memoria).
Esempio (Object)
Gestione degli eventi in Java (ActionListener, MouseAdapter): le azioni vengono associate
agli eventi attraverso un Object Adapter che implementa i metodi dellinterfaccia Listener
richiamando i metodi delloggetto che effettivamente esegue lazione.
Composite (Object)
Problema
Vogliamo gestire oggetti (Component) che possono essere sia semplici sia complessi
(composti da pi oggetti semplici, eventualmente in maniera gerarchica); si vuole rendere il
client indipendente dal fatto che stia usando componenti semplici o complessi.
Soluzione
Si definisce la classe Composite che implementa linterfaccia di Component ed ha al suo
interno un insieme di component; il Composite invoca i metodi di Component su tutti i
Component da cui costituito.
Struttura
Conseguenze
Esempio
Decorator (Object)
Problema
Vogliamo aggiungere a run-time delle responsabilit a un oggetto Component senza
cambiarne linterfaccia; non possibile usare lereditariet.
Soluzione
Si definisce una classe Decorator che implementa linterfaccia di Component ed ha al suo
interno un riferimento al Component che viene decorato; nei metodi del decorator vengono
aggiunte le pre o post-elaborazioni necessarie e quindi si richiama il metodo del
Component.
Struttura
Conseguenze
trasparente per gli utenti del Component (basta sostituire al posto dei riferimenti al
Component quelli al Decorator);
Si possono applicare pi Decorator in cascata;
I Decorator possono essere decisi a run-time ed essere aggiunti o rimossi
alloccorrenza.
Esempio
La libreria I/O di Java la quale ha una classe FilterInputStream che un Decorator (vi sono 4
ConcreteDecorator, in verde nella figura) e pu essere applicato ai componenti concreti
dellinterfaccia base InputStream (in giallo).
Facade (Object)
Problema
Vogliamo nascondere al client la complessit interna di un sistema costituito da numerosi
interfacce e classi; si vuole rendere le funzioni del sistema accessibili semplicemente
interagendo con una sola classe.
Soluzione
Si realizza una classe Facade (di facciata), la quale ha al suo interno i riferimenti agli
oggetti che compongono il sistema; il client vede solo Facade e i metodi di questoggetto
attivano le opportune operazioni del sistema.
Struttura
Facade: classe di
interfaccia tra client e
sistema.
Conseguenze
Esempio
In Java la classe org.junit.runner.JUnitCore una Facade per accedere al sottosistema di
JUnit che si occupa di lanciare i test.
Proxy (Object)
Problema
Vogliamo utilizzare un oggetto Proxy al posto di un altro oggetto Subject, in quanto
laccesso al Subject complesso e vogliamo nascondere tale complessit.
Soluzione
Si realizza un oggetto Proxy che implementa linterfaccia del Subject; invocando i metodi
del Proxy, dopo le opportune operazioni per laccesso e la comunicazione, vengono invocati
i corrispondenti metodi del Subject.
Struttura
SubjectInterface: interfaccia che
presenta le operazioni eseguibili
dalloggetto e viene utilizzato dal
client;
RealSubject: oggetto reale che
deve essere interfacciato dal Proxy;
Proxy: oggetto che implementa
linterfaccia del Subject e mantiene
al suo interno un riferimento al
RealSubject.
Conseguenze
Esempi
Remote Proxy: il Subject reale si trova in un processo diverso da quello del client o
anche su un altro computer (potrebbe anche girare su una diversa piattaforma o
essere scritto in un diverso linguaggio di programmazione); il Proxy si occupa di
utilizzare i servizi di Inter-Process-Communication e di rete per interfacciarlo.
Virtual Proxy (Lazy Instantiation): il Subject reale oneroso da istanziare,
pertanto si usa un Proxy al suo posto il quale crea il Subject reale solo quando viene
richiamato per la prima volta un metodo non gestibile direttamente dal Proxy.
Future Proxy: il Subject reale richiede molto tempo per essere creato; per evitare di
bloccare il programma, esso viene creato in un thread secondario mentre al suo
posto viene utilizzato il Proxy nel programma; se viene richiamato un metodo che il
Proxy non in grado di gestire ed il Subject reale non ancora pronto, viene
introdotta unattesa o restituito un valore nullo (le immagini in AWT vengono gestite
in questo modo).
Smart Proxy: il Subject usa meccanismi speciali per lallocazione e la deallocazione
e si vuole nasconderli al client, pertanto si usa un Proxy con meccanismi normali che
si occupa di gestire quelli speciali richiesti dal Subject (in C++ la classe String usa
uno Smart Proxy per nascondere lallocazione dinamica, il quale si occupa anche di
Soluzione
Si definisce una classe abstract che contiene lo schema dellalgoritmo allinterno di un
metodo (Template Method) che richiama altri metodi (Hook Method) per le parti che
differiscono tra diversi problemi.
Gli Hook Method possono essere abstract o avere unimplementazione di default.
Per ogni problema si crea una sottoclasse che ridefinisce i metodi hook.
Struttura
AbstractClass: definisce il metodo concreto ed i metodi hook
astratti;
ConcreteClass: implementa i metodi hook.
Conseguenze
Esempio
Implementazione
public abstract class Accumulator {
// Template method
public int compute(int a[], int n) {
int value=initialValue();
int i;
for(i=0; i<n; i++)
value=combine(value, a[i]);
return value;
}
// Hook method
public abstract int initialValue();
// Hook method
public abstract int combine(int currentValue, int element);
Soluzione
Si definisce una classe astratta Handler, i cui oggetti concreti hanno un metodo per gestire
la richiesta ed un riferimento allHandler successivo; la richiesta viene inviata alla catena di
Handler ed ognuno decider se gestirla o passarla al successivo.
Struttura
Handler: definisce
linterfaccia per
gestire le richieste
ed implementa il
collegamento al
successivo;
ConcreteHandler:
gestisce le richieste
di cui responsabile
e propaga le altre al
suo successore.
Conseguenze
Esempi
Implementazione
public abstract class Parameters {
protected Parameters next;
protected Parameters(Parameters next) {
this.next = next;
}
Command (Object)
Problema
Un sistema pu dover eseguire azioni che hanno per oggetto altre azioni del sistema
(comando undo, salvataggio di una macro, comandi di personalizzazione della barra dei
menu).
Soluzione
Si definisce una interfaccia/classe astratta Command che contiene i metodi per eseguire un
comando; ogni azione viene realizzata con una classe concreta che implementa Command.
Struttura
Conseguenze
Implementazione
public class Account {
private double balance; // Saldo del conto
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>();
}
Iterator (Object)
Problema
Si vuole consentire al client di accedere agli elementi di un aggregato senza dipendere dalla
struttura dati effettivamente utilizzata.
Soluzione
Si definisce uninterfaccia Iterator che rappresenta una posizione allinterno dellaggregato;
lIterator fornisce metodi per verificare se ci sono altri elementi, per accedere allelemento
corrente e per spostarsi nellaggregato.
Limplementazione concreta dellIterator associata allimplementazione dellaggregato:
possibile ottenere lIterator attraverso un Factory Method.
Struttura
Conseguenze
Esempio
Gli iteratori per le collezioni nella libreria standard di Java.
Observer (Object)
Problema
Vogliamo fare in modo che i cambiamenti nello stato di un oggetto Subject vengano riflessi
su altri oggetti dipendenti da esso; inoltre si vuole disaccoppiare il Subject dagli oggetti
dipendenti.
Soluzione
Si definisce uninterfaccia Observer con un metodo che viene richiamato ad ogni modifica
del Subject; gli oggetti, che implementano Observer, devono registrarsi per gli eventi a cui
sono interessati presso il Subject; a sua volta il Subject ogni qualvolta cambia il proprio
stato richiama il metodo di notifica per tutti gli Observer registrati.
Struttura
Subject: interfaccia che contiene i metodi per iscriversi e cancellarsi e la lista degli
osservatori iscritti;
ConcreteSubject: oggetto che viene osservato, il quale notifica gli osservatori in caso di
un cambio di stato;
Observer: interfaccia che contiene il metodo per aggiornare gli osservatori in caso di
modifica del Subject;
ConcreteObserver: implementa linterfaccia dellObserver definendo il comportamento in
caso di modifica del Subject.
Conseguenze
Esempi
La gestione degli eventi nella libreria AWT (i Listener hanno il ruolo di Observer,
mentre i componenti dellinterfaccia rappresentano il Subject).
La libreria Java provvede una classe (java.util.Observable) e uninterfaccia
(java.util.Observer) per implementare il pattern.
Implementazione
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();
}
}
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";
}
}
}
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");
setSize(400, 300);
canvas=new Canvas();
canvas.setBackground(Color.GREEN);
add("Center", canvas);
setVisible(true);
}
public void update(Observable subject, Object arg) {
AlertCondition alert=(AlertCondition)subject;
switch (alert.getCondition()) {
case AlertCondition.GREEN:
canvas.setBackground(Color.GREEN);
break;
case AlertCondition.YELLOW:
canvas.setBackground(Color.YELLOW);
break;
case AlertCondition.RED:
canvas.setBackground(Color.RED);
break;
default:
canvas.setBackground(Color.GRAY);
break;
}
canvas.repaint();
}
}
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();
}
}
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();
}
State (Object)
Problema
Vogliamo che il comportamento di alcune operazioni dipenda dallo stato in cui loggetto
Context si trova; inoltre si vuole evitare che la dipendenza dallo stato sia cablata nei metodi
delloggetto perch ci renderebbe complicato estendere linsieme degli stati (es. blocchi ifelse per verificare lo stato in cui ci si trova).
Soluzione
Lo stato del Context viene trasformato in un oggetto che implementa uninterfaccia State
con le operazioni che devono essere eseguite in modo diverso per ogni stato; ogni stato
diventa una sottoclasse concreta di State ed il Context mantiene un riferimento alloggetto
che rappresenta lo stato corrente, modificando tale riferimento quando cambia lo stato.
Struttura
Context: loggetto
utilizzato dal client e
mantiene un riferimento al
ConcreteState corrente;
State: interfaccia che
descrive il comportamento
associato ai diversi stati;
ConcreteState: sottoclasse
che implementa il
comportamento associato ad uno stato.
Conseguenze
Esempio
Un software di disegno varia il risultato di un click del mouse in base allo strumento
correntemente selezionato.
Implementazione
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) {
}
}
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);
}
}
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 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;
}
// . . .
}
Strategy (Object)
Problema
Vogliamo rendere il contesto in cui viene utilizzato un algoritmo indipendente da una
particolare implementazione dellalgoritmo (es. in un algoritmo di ordinamento abbiamo
bisogno di confrontare 2 oggetti e vogliamo che lalgoritmo sia indipendente dal modo in
cui viene fatta la comparazione).
Soluzione
Si definisce uninterfaccia Strategy che contiene le operazioni di cui si vuole nascondere
limplementazione e quindi per ogni implementazione si definisce una sottoclasse concreta
di Strategy; loggetto Context riceve un riferimento alla sottoclasse concreta di Strategy
utilizzata.
Struttura
Context: rappresenta
il contesto ed ha il
compito di invocare
lalgoritmo;
Strategy: interfaccia
dellalgoritmo che
viene invocata dal
Context;
ConcreteStrategy:
contiene
limplementazione
concreta
dellalgoritmo.
Conseguenze
Esempio
Per gli algoritmi di ordinamento si pu utilizzare un Comparator che rappresenta la Strategy
per la comparazione.
Implementazione
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);
// UTILIZZO:
public class Collections {
// Ordina una lista
public static List sort(List list, Comparator order) {
// . . .
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;
}
}
public class SumStrategy implements AccumulationStrategy {
public int initialValue() {
return 0;
}
// UTILIZZO:
AccumulationStrategy strategy=new SumStrategy();
Accumulator acc=new Accumulator(strategy);
int sum=acc.compute(a,n);
Visitor (Object)
Problema
Abbiamo una gerarchia di classi stabile, ma linsieme delle operazioni che vogliamo
effettuare variabile (in pratica non necessario aggiungere nuove sottoclassi, ma capita
spesso di aggiungere alla classe base nuove operazioni che devono essere implementate in
modo diverso per ogni sottoclasse).
La programmazione orientata agli oggetti efficace nel caso opposto, ossia operazioni
stabili e insieme di classi variabili.
Soluzione
Si definisce uninterfaccia/classe astratta Visitor con un metodo per ogni classe concreta
della gerarchia; per ogni operazione si definisce una sottoclasse concreta di Visitor i cui
metodi implementano loperazione da effettuare su ciascun tipo di elemento.
La classe base della gerarchia avr un metodo accept che riceve in ingresso un Visitor; le
classi concrete della gerarchia implementano tale metodo richiamando il metodo del Visitor
che corrisponde al tipo di elemento considerato, passandogli come riferimento lo stesso
oggetto corrente this.
Struttura
Conseguenze
Implementazione
public abstract class User {
public String getIpAddress() {
return "10.0.77.1";
}
public abstract void accept(UserVisitor visitor);
}
public interface UserVisitor {
void visitAnonymous(AnonymousUser user);
void visitRegular(RegularUser user);
void visitDeluxe(DeluxeUser user);
}
public class AnonymousUser extends User {
public void accept(UserVisitor visitor) {
visitor.visitAnonymous(this);
}
}
public abstract class NamedUser extends User {
private String name;
public NamedUser(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
// ...
// ...