Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi...

84
Tecniche di Progetto (a.k.a. Design Patterns)

Transcript of Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi...

Page 1: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Tecniche di Progetto(a.k.a. Design Patterns)

Page 2: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Progettazione Object-Oriented

Passi della prassi

• Definizione delle classi

• Determinazione delle responsabilità di ciascuna classe

• Descrizione delle relazioni tra classi

Page 3: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Scoperta delle classi

• Classi rappresentano concetti ed entità entità concrete: conti bancari, forme geometriche, … concetti astratti: streams …

Page 4: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Relazioni tra classi

• Ereditarietà (sottotipo)

• Aggregazione

• Dipendenza

Page 5: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Ereditarietà

• Relazione is-a

• Stabilita tra una classe generale ed una sua specializzazione ogni savings accoung è un bank account ogni cerchio è una ellisse …

Continued…

Page 6: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Aggregazione

• Relazione has-a

• Oggetti di una classe contengono riferimenti ad oggetti di un altra classe

• Ogni automobile ha una ruota (in realtà ne ha quattro … )

• Da non confondere con ereditarietà

Page 7: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

is-a vs has-a

class Car extends Vehicle{ . . . private Tire[] tires;}

Page 8: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Dipendenza

• Una relazione di uso

• Esempio: molte delle applicazioni che abbiamo visto dipendono dalla classe Scanner

• Aggregazione è una forma più forte di dipendenza

Page 9: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Progettazione Object-Oriented

Passi della prassi

• Definizione delle classi

• Determinazione delle responsabilità di ciascuna classe

• Descrizione delle relazioni tra classi

Obiettivi

• Garantire astrazione

• Massimizzare riuso

Page 10: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

• Progetto componenti astratte pattern: iterator

• Progetto di componenti riusabili/polimorfe tecniche comuni di refactoring e generalizzazione patterns: template, strategy, visitor, decorator …

Page 11: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Progetto di componenti astratte

TIPI DI DATO: Abstract vs Concrete

• Lista astratta Una sequenza ordinata di elementi di un certo tipo

che si possono enumerare con un iteratore

• Lista concreta Una sequenza di nodi che puntano ad oggetti di un

certo tipo e sono collegati mendiante riferimenti

Page 12: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Una lista astratta

Page 13: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Una lista concreta

Page 14: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Un ListIterator astratto

Page 15: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Un ListIterator concreto

Page 16: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Pattern – Iterator

ConcreteCollection<E>

iterator(). . .

AbstractCollection<E>

iterator(). . .

return new ConcreteIterator<E>(this)

Client Iterator<E>

next()hasNext()

ConcreteIterator<E>

Page 17: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Progetto di componenti polimorfe

• Polimorfo ~ Riutilizzabile

• Generics forniscono un meccanismo diretto per ottenere componenti riutilizzabili

• Ereditarietà e aggregazione possono essere altrettanto efficaci alcune tecniche standard codificate in design patterns

Page 18: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Refactoring

• Identificare segmenti di codice ricorrenti che realizzano la medesima logica

• Definire una nuova componente generica che realizza quella logica in modo univoco

• Ristrutturare il codice così da sostituire le ripetizioni di codice con riferimenti alla componente generica

Page 19: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Refactoring di una classe

class Computation // Prima del refactoring

{ void method1(...) { ... step1(); step2(); step3(); ... }

void method2(...) { ... step1(); step2(); step3(); ... }}

Continua…

Page 20: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Refactoring di una classeclass Computation // Dopo del refactoring { void private computeAll() { step1(); step2(); step3(); }

void method1(...) { ... computeAll(); ... }

void method2(...) { ... computeAll(); ... }}

Page 21: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Refactoring di più classi

class ComputationA { void method1(...) {...; step1(); step2(); step3(); ...}}

class ComputationB { void method2(...) {...; step1(); step2(); step3(); ...}}

• Codice duplicato su diverse classi

Continua…

Page 22: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Refactoring di più classi

• Refactoring via ereditarietà

class Common { void commonSteps() { step1(); step2(); step3(); }}

class ComputationA extends Common { void method1(...) { ... ; commonSteps(); ... }}

class ComputationB extends Commom { void method2(...) { ... ; commonSteps(); ... }}

Continua…

Page 23: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

• Refactoring via aggregazione e delegation

Refactoring di più classi

class Helper { void commonSteps() { step1(); step2(); step3(); }}

class ComputationA{ Helper help; void method1(...) { ... ; help.commonSteps(); ... }}

class ComputationB{ Helper help; void method2(...) { ... ; help.commonSteps(); ... }}

Page 24: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Refactoring – UML

ComputationA

method1()method2()

ComputationB

method1()method2()

Continua…

Page 25: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

• Refactoring via inheritance

Refactoring – UML

ComputationA

method1()method2()

ComputationB

method1()method2()

Common

commonSteps()

Continua…

Page 26: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

• Refactoring via aggregazione e delegation

Refactoring – UML

ComputationA

method1()method2()

ComputationB

method1()method2()

Helper

commonSteps()

helperhelper

Page 27: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Una situazione più complessa

class ContextA { void method(...) { <codice comune 1>; stepA(); <codice comune 2>; }}

class ContextB { void method(...) { <codice comune 1>; stepB(); <codice comune 2>; }}

Page 28: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Generalizziamo la soluzione?

class Common { commonCode1() { <codice comune 1> } commonCode2() { <codice comune 2> }}

class ContextA extends Common { void method(...) {commonCode1(); stepA(); commonCode2();}}

class ContextB { void method(...) {commonCode1(); stepB(); commonCode2();}}

Continua…

Page 29: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Generalizziamo la soluzione?

• Uhm …

• se i due frammenti di codice comune sono strettamente dipendenti tra loro possibile che separarli generi errori rompe il flusso del controllo naturale peggiora la leggibilità del codice

• se i due frammenti sono parte dello stesso comando composto (ad esempio, un ciclo) non realizzabile

Page 30: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Esempio: due Plotters

• Plotter per la funzione sin(x)

class PlotSin { . . .

protected void plotFunction(Graphics g) {

for (int px = 0; px < d.width; px++) {double x = (double)(px - xorigin) / (double)xratio;double y = Math.sin(x);int py = yorigin - (int) (y * yratio);g.fillOval(px - 1, py - 1, 3, 3);

}}

Continua…

Page 31: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Esempio: due Plotters

• Plotter per la funzione cos(x)

class PlotCos { . . .

protected void plotFunction(Graphics g) {

for (int px = 0; px < d.width; px++) {double x = (double)(px - xorigin) / (double)xratio;double y = Math.cos(x);int py = yorigin - (int) (y * yratio);g.fillOval(px - 1, py - 1, 3, 3);

}}

Page 32: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Una situazione più complessa

class ContextA { void method(...) { <codice comune 1>; stepA(); <codice comune 2>; }}

class ContextB { void method(...) { <codice comune 1>; stepB(); <codice comune 1>; }}

Page 33: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Refactoring con il pattern Template

abstract class Common{ void methodoTemplate (...) { <codice comune 1>; metodoHook(...); <codice comune 2> } abstract void metodoHook();}

class ContextA extends Common { void metodoHook(...) { stepA(); }}

class ContextB extends Common { void metodoHook(...) { stepB(); }}

Page 34: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Pattern Template

classe Concreta

methodHook1()methodHook2()

classe Generica

metodoTemplate()metodoHook1();metodoHook2();

. . . metodoHook1();. . . methdoHook2(). . .

Page 35: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Esempio: progetto di animazioni

• Una applicazione del pattern template

• Fattorizza la logica di animazione in una classe astratta

• Lascia la definizione dell’immagine da animare alle sottoclassi concrete

• Vediamo la classe astratta Animator due classi concrete

•BouncingBall, DigitalClock

Page 36: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Animatorpublic abstract class Animator

extends JComponent implements ActionListener { private int delay; private Timer T;

protected Animator(int delay) { this.delay = delay; setPreferredSize(new Dimension(getWidth(),getHeight())); T = new Timer(delay, this); } // schema di animazione: guidata dagli eventi del timer public void animate(){ T.start(); } public void actionPerformed(ActionEvent event){ repaint(); }

// metodo Hook public abstract void paintComponent(Graphics g);}

Page 37: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Domanda

• Perché la classe Animator è abstract ?

• Quale è il metodo template?

• Quale è il metodo hook?

Page 38: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Risposta

• E’ abstract perché non definisce il metodo paintComponent(), che gioca il ruolo di metodo hook in questa implementazione

• Il metodo template è actionPerformed() (che invoca paintComponent() via repaint())

Page 39: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

DigitalClock

public class DigitalClock extends Animator { private Font font = new Font("Monospaced", Font.BOLD, 48); private Color color = Color.GREEN;

private int width, height;

public DigitalClock(int delay, int width, int height) {

super(delay);this.width = width;this.height = height;

} . . .

Continua…

Page 40: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

DigitalClock

// metodo Hook public void paintComponent(Graphics g) { Calendar calendar = Calendar.getInstance(); int hour = calendar.get(Calendar.HOUR_OF_DAY); int minute = calendar.get(Calendar.MINUTE); int second = calendar.get(Calendar.SECOND);

String time = “ ” + (hour / 10) + (hour % 10) + ":" + (minute / 10) + (minute % 10) + ":" + (second / 10) + (second % 10);

g.setFont(font); g.setColor(color); g.drawString(time, 50, 150); }} // chiude DigitalClock

Page 41: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

DigitalClock

Page 42: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

BouncingBall

public class BouncingBall extends Animator { // la pallina private Ellipse2D.Double ball; private final int DIAM = 30;

// ampiezza dell'oscillazione private int jump;

// posizione corrente private int x, y;

// direzione dela prossima oscillazione 1 = dx, -1 = sx private int dir = 1;

Continua…

Page 43: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

BouncingBall

// costruttore public BouncingBall(int delay, int width, int height) {

super(delay);int lmargin = (int)(width * 0.1);int rmargin = (int)(width - DIAM - lmargin);jump = rmargin - lmargin;x = lmargin;y = (int)(height - DIAM) /3;ball = new Ellipse2D.Double(x,y,DIAM,DIAM);

}

Continua…

Page 44: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

BouncingBall

// metodo Hook public void paintComponent(Graphics g) {

Graphics2D g2 = (Graphics2D)g;// calcola nuova posizionex = x + dir * jump; // inverti la direzionedir = -dir; ball.setFrame(x,y,DIAM,DIAM);g2.setColor(Color.BLUE);g2.fill(ball);

}} // fine BouncingBall

Continua…

Page 45: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

BouncingBall

Page 46: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Esempio: progetto di un plotter

• Ancora applicazione del pattern template

• Fattorizza il comportamento grafico in una classe astratta

• Lascia la definizione della funzione da tracciare alle sottoclassi concrete

• Vediamo la classe astratta Plotter due classi concrete PlotSine, PlotCosine

Continua…

Page 47: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Esempio: progetto di un plotter

Page 48: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Plotter

public abstract class Plotter extends JFrame{ . . .

public Plotter(Dimension dim) { . . . }

public void paintComponent(Graphics g) { drawCoordinates(g); plotFunction(g); }

protected void drawCoordinates(Graphics g) { . . . }

. . .

Continua…

Page 49: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Plotter

// metodo templateprotected void plotFunction(Graphics g) {

for (int px = 0; px < d.width; px++) { double x = (double)(px - xorigin) / (double)xratio; double y = func(x); int py = yorigin - (int) (y * yratio); g.fillOval(px - 1, py - 1, 3, 3);

}}

// metodo hookpublic abstract double func(double x);

} // end Plotter

Page 50: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

I plotter concreti

• Implementano il metodo hook

public class PlotSine extends Plotter {

public double func(double x) { return Math.sin(x);}

}

public class PlotCosine extends Plotter {

public double func(double x) { return Math.cos(x);

}}

Page 51: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Un plotter multiplo

• Per il momento l’applicazione assegna ad ogni plotter una sola funzione

• Nuova funzionalità permettere il plotting di più funzioni

contemporaneamente

• Vincolo: ancora flessibilità: vogliamo disaccoppiare le funzioni

da tracciare dal plotter stesso

Page 52: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Soluzione con Template

public class DoublePlotter {

// due metodi Hook public abstract double func1(double x);public abstract double func2(double x); ...

}

public class TriplePlotter {

// tre metodi hookpublic abstract double func1(double x);public abstract double func2(double x);public abstract double func3(double x);

...}

Continua…

Page 53: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Soluzione con Template ?

• Poco elegante: una classe plotter per ciascun numero di funzioni da tracciare

• Poco flessibile: dobbiamo restringerci ad un numero fissato di funzioni, mentre vorremmo definire un MultiPlotter generico

• Troppi poco …

Page 54: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Soluzione con Strategy

• come Template disaccoppia le funzioni da tracciare dal plotter

• ma invece di rappresentare ogni funzione come un metodo, rappresenta come un oggetto

Page 55: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Oggetti Function

interface Function{ double apply(double x);}public class Sine implements Function{ public double apply(double x) { return Math.sin(x); }}public class Cosine implements Function { public double apply(double x) { return Math.cos(x); }}

• Sfruttiamo dynamic dispatch per invocare il metodo apply() corretto

Page 56: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Plotter

• Vediamo le conseguenze di questa idea nel progetto del plotter

Page 57: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Plotter

import javax.swing.*;

public abstract class Plotter extends JFrame {

. . . private Function fun;

public void paint(Graphics g) { drawCoordinates(g); plotFunction(g);

}

public Plotter (Dimension dim) { . . . }

. . . Continua…

Page 58: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Plotter

protected void plotFunction(Graphics g) {

for (int px = 0; px < d.width; px++) { double x = (double)(px - xorigin) / (double)xratio; double y = fun.apply(x); int py = yorigin - (int) (y * yratio); g.fillOval(px - 1, py - 1, 3, 3);

}}

} // end Plotter

Page 59: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Pattern Strategy

StrategyyA

metodoHook()

Strategy

metodoHook()

. . . strategy.metodoHook();. . .

Contesto

metodoDiContesto()

stragegy

StrategyB

metodoHook()

Page 60: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Pattern Strategy su Plotter

Sine

apply()

Function

apply()

. . . fun.apply();. . .

Plotter

plotFunction()

fun

Cosine

apply()

Page 61: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

MultiPlotter

Continua…

• Ora generalizziamo per creare il plotter multiplo

Page 62: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

MultiPlotterimport javax.swing.*;public abstract class MultiPlotter extends JFrame {

. . . private List<Function> fns = new ArrayList<Function>;private List<Color> colors = new ArrayList<Color>;

public void paint(Graphics g) { drawCoordinates(g); plotFunction(g);

}

public MultiPlotter (Dimension dim) { . . . }

public void addFunction(Function f, Color c) { fns.add(f); colors.add(c); } . . .

Continua…

Page 63: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

MultiPlotter

...protected void plotFunction(Graphics g) { for (int i = 0; i < fns.size(); i++) {

if (fns.get(i) != null) { Color c = colors.tet(i); if (c != null) g.setColor(c); else g.setColor(Color.black); for (int px = 0; px < d.width; px++) { double x = (double) (px - xorigin) / (double) xratio; double y = fns.get(i).apply(x); int py = yorigin - (int) (y * yratio); g.fillOval(px - 1, py - 1, 3, 3);

}}} }

Page 64: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Classe concreta PlotSineCosine

public class PlotSineCosine extends MultiPlotter {

public PlotSineCosine() { // ricordate: Sine e Cosine implementano Function addFunction(new Sine(), Color.green); addFunction(new Cosine(), Color.blue);

}}

Page 65: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Caso di studio: animazione di algoritmi

• La struttura di animazione generica vista negli esempi del DigitalClock e BouncingBall precedenza non è sempre adeguata

• Nell’animazione di un algoritmo animazione deve essere gestibile dall’algoritmo chiamata a repaint(), deve essere controllata

dell’esecuzione, non ad istanti stabiliti dall’esterno

• Vogliamo comunque disaccoppiamento tra algoritmo e la struttura di animazione

Page 66: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Soluzione 1 – Template

SortAnimator

algorithm() sort()

AlgorithmAninator

animate()algorithm() . . .

algorithm(). . .

scramble()sort();. . .

BubbleSortAnimator

sort()

QuickSortAnimator

sort()

Page 67: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

AlgorithmAnimator

public abstract class AlgorithmAnimator extends JComponent { public AlgorithmAnimator(int d) { delay = d; }

// metodi template: animate() & pause() public void animate() { algorithm(); }

final protected void pause() {try { Thread.currentThread().sleep(delay); } catch (InterruptedException e) { }repaint();

} // metodi hook: paintComponent() & algorithm() abstract protected void algorithm();

private int delay;}

Page 68: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

SortAnimator

public class SortAnimator extends AlgorithmAnimator {

// l’array da ordinare protected int arr[]; private void swap(int a[], int i, int j) { int T; T = a[i]; a[i] = a[j]; a[j] = T; }

protected void scramble() { arr = new int[getPreferredSize().height / 6]; for (int i = arr.length; --i >= 0;) { arr[i] = (int)(i * Math.random());}

}

Page 69: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

SortAnimator

// metodo hook protected void paintComponent(Graphics g) {

Dimension d = getSize(); g.setColor(Color.BLACK);g.fillRect(0, 0, d.width, d.height); g.setColor(Color.GREEN);int y = d.height - 10; double f = d.width / (double) arr.length; for (int i = arr.length; --i >= 0; y -= 5) { g.fillRect(0, y, (int)(arr[i] * f), 3);}

}

Page 70: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

SortAnimator

// metodo hook final public void algorithm() { scramble(); JOptionPane.showMessageDialog(this, "Start animation"); sort(arr); JOptionPane.showMessageDialog(this,"Done! "); } // nuovo template protected abstract void sort(int[] a);

} // Chiude SortAnimator

Page 71: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

BubbleSortAnimator

public class BubbleSortAnimator extends SortAnimator { public BubbleSortAnimator(int delay) {

super(delay); }

// override del metodo nella superclasse protected void sort(int[] a) {

for (int i = a.length; --i >= 0; ) for (int j = 0; j < i; j++) {

if (a[j] > a[j+1]) swap(a, j, j + 1); pause();

} }}

Page 72: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Valutazione

• Implementazione molto semplice

• Supporta diversi algoritmi

• Ma …• La classe SortAnimator è poco coesa• fornisce metodi legati ad aspetti algoritmici e di

visualizzazione

• Separare i due aspetti aumenta la flessibilità • nuova soluzione

Page 73: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Soluzione 2 – Strategy

SortAnimator

animate()

AlgorithmAninator

animate()pause()

. . . animator.pause(). . .

sorter.sort(). . .

BubbleSort

sort()

QuinckSort

sort()

SortingAlgorithm

sort()sorter

animator

Page 74: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

AlgorithmAnimator

public abstract class AlgorithmAnimator extends JComponent { private int delay;

public AlgorithmAnimator(int delay){this.delay = delay;}

// template degenere, no hooks public abstract void animate();

final protected void pause() {try { Thread.currentThread().sleep(delay); } catch (InterruptedException e) { }repaint();

}}

Page 75: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

SortAnimator

public class SortAnimator extends AlgorithmAnimator {

// l’array da ordinare private int arr[];

// l'algoritmo che esegue il sorting protected SortingAlgorithm sorter;

protected SortAnimator(int delay, SortingAlgorithm sorter) {

super(delay); this.sorter = sorter; sorter.setAnimator(this);

}

Page 76: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

SortAnimator

public void animate() { scramble(); JOptionPane.showMessageDialog(this, "Start"); sorter.sort(arr); JOptionPane.showMessageDialog(this,"Done! "); }

// metodi scramble e paintComponent invariati . . . }

Page 77: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

SortingAlgorithm

public abstract class SortingAlgorithm {

protected SortAnimator animator;

public setAnimator(SortAnimator animator) {this.animator = animator;

}

public abstract void sort(int[] a);

protected void swap(int a[], int i, int j) { . . . }}

Page 78: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

BubbleSort

public class BubbleSort extends SortingAlgorithm { public void sort(int[] a) {

for (int i = a.length; --i >= 0; ) for (int j = 0; j < i; j++) {

if (a[j] > a[j+1]) swap(a, j, j + 1);// accesso protected al

// campo della superclasse animator.pause();

} }}

Page 79: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Valutazione

• La struttura della classe SortAnimator è migliore

• Ma … ci sono ulteriori misure per migliorare la coesione il metodo di visualizzazione dell’array può essere

separato dall’algoritmo e dal meccanismo di animazione

più flessibile

Page 80: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Soluzione 3 – Strategy2

SortAnimator

animate()

AlgorithmAninator

animate()pause()

BubbleSort

sort()

QuinckSort

sort()

SortingAlgorithm

sort()

theDisplayDisplayMethod

display()

DisplayMethod

display()

DisplayMethod

display()

ConfigSortAnimator

Page 81: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Soluzione 3 – Strategy2

• Classi AlgorithmAnimator, Sorting Animator

• Gerarchia SortingAlgorithm

• Invariate

Page 82: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

ConfigurableSortAnimator

public class ConfigurableSortAnimator extends SortAnimator{ // il visualizzatore vero e proprio protected DisplayMethod theDisplay;

protected ConfigurableSortAnimator(int delay, SortingAlgorithm sorter, DisplayMethod display) {

super(delay,sorter);theDisplay = display;

}

protected void paintComponent(Graphics g) {Dimension d = getSize(); int[] a = getArray();theDisplay.display(a,d,g);

}}

Page 83: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

DisplayMethod

public interface DisplayMethod{ public void display(int[] arr, Dimension d, Graphics g);}

public class VDisplay implements DisplayMethod { public void display(int[] arr, Dimension d, Graphics g) {

. . . }}

Page 84: Tecniche di Progetto (a.k.a. Design Patterns). Progettazione Object-Oriented Passi della prassi Definizione delle classi Determinazione delle responsabilità

Frameworks

• Tipicamente: insieme di classi astratte ed interfacce

• Forniscono applicazioni semi-complete

• Da specializzare

• Progettate cercando di garantire i principi di astrazione e di favorire il riuso mediante l’applicazione di design patterns come quelli che abbiamo visto