Linguaggi e Traduttori Relazione n. 3 Indice I Parte Descrizione Analisi Progetto Implementazione Casi d’uso Concetti acquisiti II Parte Descrizione Analisi Progetto Implementazione Casi d’uso Concetti acquisiti Gardelli Luca II anno DU Ingegneria Informatica di Cesena [email protected] Strumenti utilizzati: Forte for Java CE Java SDK 1.3 I Parte Descrizione: Creare le classi necessarie ad un componente software per disegnare enti geometrici partendo dall’astrazione SimpleDrawPad. Analisi: 1. Creare una classe ADT DrawPad che sia in grado di disegnare linee, punti cerchi, rettangoli, quadrati e triangoli basandosi sull’astrazione SimpleDrawPad. Di essa viene fornita documentazione ed i files *.class, ma non i files sorgente. 2. Sviluppare quindi un componente software che ne testi il funzionamento disegnando alcune figure di differenti colori e spessori. NOTA SimpleDrawPad permette di creare una finestra, ove disegnare delle linee e dei punti, impostando lo spessore ed il colore del tratto. E’ inoltre possibile nascondere la finestra e cancellarne il contenuto. Progetto: DrawPad.java Avendo a disposizione la classe SimpleDrawPad conviene prima analizzare quali sono i servizi che rende disponibili al cliente. La classe SimpleDrawPad mette a disposizione i metodi necessari per costruire, mostrare, nascondere e cancellare una “lavagna”. Si occupando di questo rispettivamente il costruttore ed i metodi show(), hide() e clear(). Inoltre permette di disegnare linee e punti tramite i metodi public void drawLine(int x0, int y0, int x1, int y1) public void drawPoint(int x, int y) Rende anche possibile impostare lo spessore ed il colore con cui disegnare public void setCurrentThickness(int thickness) public void setCurrentColor(float r, float g, float b) Converrà quindi che la classe DrawPad erediti dalla classe SimpleDrawPad risparmiando notevolmente in fase di implementazione. Veniamo ora al cuore della classe da sviluppare. L’idea di fondo è di realizzare un metodo che sia in grado di disegnare il maggior numero di poligoni regolari, utilizzando il quale si creeranno metodi specifici per ogni figura. Questo metodo comunque sarà privato in quanto non viene richiesto che sia disponibile all’esterno, ma necessario implementazione. Chiamiamo questa funzione drawPoly: per disegnare un poligono sono necessari le coordinate del centro, il raggio del cerchio in cui è inscritto ed il numero di lati. private void drawPoly(int xc, int yc, int radius, int sides) Partendo da questo metodo si possono dunque realizzare le funzioni specifiche che realizzino dei poligoni. In particolare ho implementato i metodi per disegnare cerchi, triangoli, pentagoni e ottagoni. Tutti richiedono la posizione del centro: il cerchio richiede il raggio mentre i poligoni accettano la lunghezza del lato in quanto è più intuitivo per l’utente. public void drawCircle(int xc,int yc,int radius) public void drawTriangle(int xc,int yc,int l) public void drawPentagon(int xc, int yc, int l) public void drawOctagon(int xc, int yc, int l) Nonostante gli ultimi due non venissero richiesti li ho aggiunti per mostrare l’efficacia e la generalità dell’approccio utilizzato. Da notare come anche il quadrato potesse essere sviluppato utilizzando il metodo drawPoly, ma ho preferito utilizzare la primitiva rettangolo. Il rettangolo non può essere derivato da drawPoly in quanto non è regolare. Il metodo che si occupa della sua creazione ha la seguente signature: public void drawRectangle(int xl, int yl, int xr, int yr) Siccome in tutte le applicazioni grafiche il rettangolo viene costruito con i vertici alto-sinistra, basso-destra, ho scelto di non confondere il cliente mantenendo questo “standard”. Siccome il quadrato è un particolare rettangolo converrà rifarsi a quest’ultimo per l’implementazione. Il metodo accetta il vertice in alto a sinistra e la lunghezza del lato. public void drawSquare(int x0,int y0,int l) L’ultimo metodo è necessario alla gestione interna (quindi private): si occupa della conversione di un lato di un poligono regolare nel raggio del cerchio in cui è inscritto. private int sideToRadius(int l,int sides) Mentre è più facile per l’utente pensare in termini di lunghezza del lato piuttosto che del raggio del cerchio in cui è iscritto il poligono, l’algoritmo implementativo risulta più semplice partendo dal raggio. Test.java Il componente software Test si occuperà di testare la classe DrawPad. Non necessità di particolari accorgimenti. Dovrà solo contenere un metodo, il main in cui avverranno tutte le chiamate ai metodi di un oggetto DrawPad. public static void main (String args[]) Implementazione: DrawPad.java La classe DrawPad utilizzerà le classi Math e SimpleDrawPad, per questo è necessario importare java.util.* e tools.*. tools è il package in cui è definito SimpleDrawPad. La classe eredita da SimpleDrawPad: questo si ottiene con la parola chiave extends. Analizziamo il costruttore. DrawPad ne definisce solo uno che non accetta parametri. Inoltre la classe non deve inizializzare nulla al proprio interno, ma deve comunque inizializzare gli oggetti che eredita dalla classe padre. super() si occupa di richiamare il costruttore della classe padre in quanto lui solo sa come inizializzarne un oggetto. Questo inoltre permette di risparmiare codice, che comunque potrebbe non comportarsi nella maniera più corretta. Si arriva quindi al cuore della classe: il metodo drawPoly. Questo metodo si occupa di disegnare un poligono regolare basandosi sulle coordinate del centro, sul raggio del cerchio in cui si inscrive e sul numero di lati. Si definisce per prima cosa l’angolo al centro (alpha) di ogni triangolo isoscele che forma il poligono regolare. Si stabilisce un punto di partenza, che nel mio caso è sulla verticale del centro distante da esso un raggio (radius). Gli altri punti si ottengono per rotazione delle coordinate rispetto al centro del poligono dell’ angolo alpha. Questo si può implementare semplicemente con un cilo for e con opportuni calcoli trigonometrici. Siccome il display di un computer è formato da unità elementari (pixel) si sono utilizzate per lo più variabili intere. Questo presenta degli inconvenienti che si manifestano nei poligoni con un grande numero di lati. Le approssimazioni infatti causano l’imperfetta chiusura del poligono difetto a cui si può ovviare manualmente connettendo i due estremi con una linea. Consideriamo ora il metodo drawCircle. Questo disegna un cerchio basandosi sulle coordinate del centro e il raggio. Matematicamente parlando un cerchio è un poligono con un numero infinito di lati. A causa della discretizzazione della superficie di un display rappresentare un cerchio perfetto è impossibile: ci limiteremo ad approssimarlo con uno numero sufficientemente alto di lati. Questa è la soluzione adottata nella computer grafica. Il metodo drawCircle richiama quindi drawPoly con una impostazione predefinita di 70 lati, che restituisce un risultato sufficientemente accurato. I metodi drawTriangle, drawPentagon, drawOctagon sono implementativamente simili. Innanzi tutto ricavano la dimensione del raggio in cui sono inscritti a partire dalla lunghezza del lato. Questo viene svolto dal metodo sideToRadius che discuterò in seguito. Quindi richiamano anch’essi la funzione drawPoly passandole il numero appropriato di lati. Il metodo sideToRadius ha come compito quello di ricavare la lunghezza del raggio della circonferenza in cui si inscrive il poligono dalla lunghezza del lato. Questa conversione è necessaria in quanto mi è sembrato più intuitivo per un cliente pensare in termini di lunghezza del lato piuttosto che in base al raggio: mentre l’algoritmo che genera il poligono è molto più semplice da implementare ragionando sul raggio. Il metodo è stato definito privato in quanto non necessario all’esterno. Passiamo ora al rettangolo. Il metodo drawRectangol si occupa di disegnare un rettangolo in base alle coordinate dei punti alto-sinistra e basso-destra, dai quali ricava i vertici e li interconnette con delle linee. Anche in questo caso la scelta dei due vertici è basata su una consuetudine perpetrata nel campo della computer grafica. Il quadrato viene disegnato dal metodo drawSquare che si basa sulla primitiva rettangolo in quanto geometricamente un quadrato è un caso particolare di rettangolo. Il metodo richiede le coordinate del vertice in alto a sinistra la lunghezza del lato. Da notare come anche il quadrato poteva essere realizzato a partire da drawPoly, in quanto è un poligono regolare con quattro lati. Codice (DrawPad.java): /* * Needed by Math and SimpleDrawPad */ import java.util.*; import tools.*; /** * This class provide methods to draw circles, octagons, pentagons, * triangles, squares, rectangles, lines and points in a window * * @author Luca Gardelli * @version 1.0 */ public class DrawPad extends SimpleDrawPad { /** * Default constructor * Do not need to initialize anything, just call parent constructor */ public DrawPad() { super(); } /** * Draw any type of regular polygon * * @param xc : x center coordinate (int value) * @param yc : y center coordinate (int value) * @param radius : Radius of the circle circumscribed (int value) * @param sides : Number of sides (int value) */ private void drawPoly(int xc, int yc, int radius, int sides) { double alpha=360/sides; int x0=xc; //starting x int y0=yc-radius; //starting y int x1,y1; for (int i=1;i<=sides;i++){ //rotate the point x1=(int)(xc+radius*Math.sin(i*alpha*Math.PI/180)); y1=(int)(yc-radius*Math.cos(i*alpha*Math.PI/180)); //connect the points (x0-x1,y0-y1) drawLine(x0,y0,x1,y1); x0=x1;y0=y1; } //correct any error drawLine(x0,y0,xc,yc-radius); } /** * Return the radius length of a regular polygon having l side * length and sides number of sides * * @param l : side length (int value) * @param sides : sides number (int value) */ private int sideToRadius(int l,int sides) { return (int)(l/(2*Math.cos((90-180/sides)*Math.PI/180))); } /** * Draw a rectangle of current thickness, color based on upper * left corner and bottom right one * * @param xl : upper left corner (x coordinate) (int value) * @param yl : upper left corner (y coordinate) (int value) * @param xr : bottom right corner (x coordinate) (int value) * @param yr : bottom right corner (y coordinate) (int value) */ public void drawRectangle(int xl, int yl, int xr, int yr) { drawLine(xl,yl,xr,yl); drawLine(xr,yl,xr,yr); drawLine(xr,yr,xl,yr); drawLine(xl,yr,xl,yl); } /** * Draw a circle of current thickness, color base on center * and radius * * @param xc : x center coordinate (int value) * @param yc : y center coordinate (int value) * @param radius : circle radius (int value) */ public void drawCircle(int xc,int yc,int radius) { drawPoly(xc,yc,radius,70); } /** * Draw a square of current thickness, color based on upper * left corner and side length * * @param x0 : upper left corner (x coordinate, int value) * @param y0 : upper left corner (y coordinate, int value) * @param l : side length (int value) */ public void drawSquare(int x0,int y0,int l) { drawRectangle(x0,y0,x0+l,y0+l); } /** * Draw a regular triangle of current thickness, color based * on center coordinates and side length * * @param xc : xc center coordinate (int value) * @param yc : yc center coordinate (int value) * @param l : side length (int value) */ public void drawTriangle(int xc,int yc,int l) { //calculate the radius by side length value int radius=sideToRadius(l,3); drawPoly(xc,yc,radius,3); } /** * Draw a regular pentagon of current thickness, color based * on center coordinates and side length * * @param xc : xc center coordinate (int value) * @param yc : yc center coordinate (int value) * @param l : side length (int value) */ public void drawPentagon(int xc, int yc, int l) { //calculate the radius by side length value int radius=sideToRadius(l,5); drawPoly(xc,yc,radius,5); } /** * Draw a regular octagon of current thickness, color based * on center coordinates and side length * * @param xc : xc center coordinate (int value) * @param yc : yc center coordinate (int value) * @param l : side length (int value) */ public void drawOctagon(int xc, int yc, int l) { //calculate the radius by side length value int radius=sideToRadius(l,8); drawPoly(xc,yc,radius,8); } } Test.java Il componente software Test si occupa di testare la classe DrawPad precedentemente realizzata. Siccome non utilizza direttamente la classe SimpleDrawPad non è necessario importare nulla. Scorrendo il codice si può comprendere come utilizzare la classe DrawPad. Occorre innanzi tutto istanziarne un oggetto, quindi mostrarlo. Si può poi impostare lo spessore (2) ed il colore (rosso = 1f,0,0). Ho disegnato un triangolo un rettangolo una linea ed un punto con i valori correnti di spessore e colore. Vi è poi un blocco di codice che forza il programma ad attendere qualche secondo prima di continuare. Tramite clear() si è pulita la “lavagna”, quindi si sono reimpostati lo spessore (1) ed il colore (azzurro = 0,0.4f,1f). Si sono disegnati un cerchio un quadrato un pentagono ed un ottagono quindi si è atteso qualche secondo prima di lanciare l’istruzione per uscire dal programma (System.exit(0)). Codice (Test.java): /* * Test.java * * Created on 17 maggio 2001, 22.27 */ /** * * @author Luca Gardelli * @version 1.0 */ public class Test { public static void main (String args[]) { //Create a new pad DrawPad pad = new DrawPad(); //Show the pad pad.show(); //Set thickness and color pad.setCurrentThickness(2); pad.setCurrentColor(1f,0,0); pad.drawTriangle(220,220,80); //draw a triangle pad.drawRectangle(20,90,80,170); //draw a rectangle pad.drawLine(10,10,4,300); pad.drawPoint(350,350); //draw a line //draw a point //Wait 4 seconds try { Thread.currentThread().sleep(4000); } catch (Exception ex){ } //Clear the pad pad.clear(); //Set thickness and color pad.setCurrentThickness(1); pad.setCurrentColor(0,0.4f,1f); pad.drawCircle(300,120,50); pad.drawSquare(1,1,40); pad.drawOctagon(100,150,35); pad.drawPentagon(200,300,50); //draw a circle //draw a square //draw a octagon //draw a pentagon //Wait 4 seconds try { Thread.currentThread().sleep(4000); } catch (Exception ex){ } // Exit System.exit(0); } } Casi d’uso: Eseguendo il programma Test si ottiene il seguente output: e dopo 4 secondi…. Quindi la finestra si è chiusa. Concetti acquisiti Durante lo svolgimento della relazione e la stesura del codice mi si sono presentati alcuni problemi: Ereditarietà: la necessità del meccanismo di ereditarietà nello sviluppo dell’astrazione DrawPad è piuttosto evidente. La necessità di estendere programmi e di soddisfare problemi più complessi implicherebbe il sobbarcarsi di lavoro già fatto, ma soprattutto riscrivere codice già funzionante! L’ereditarietà permette di riutilizzare efficacemente il lavoro già svolto implementando solo le estensioni e di organizzare gerarchicamente le classi. Riuso delle astrazioni: l’ereditarietà non è l’unico modo per riutilizzare le classi. In DrawPad è stata utilizzata la classe Math senza nessun meccanismo di ereditarietà. Anche in questo caso il lavoro del programmatore è snellito grazie alla presenza di librerie di classi già pronte all’utilizzo: questo permette di concentrarsi di più sul problema piuttosto che sulla costruzione degli strumenti. - INDEX - II Parte Descrizione: Derivare, dalla classe astratta Shape, delle classi concrete relative al figure che siano in grado di disegnarsi: utilizzando l’astrazione SimpleDrawPad testare le classi create. Analisi: 1. Basandosi sulla classe astratta Shape (fornita di documentazione), occorrerà derivare tante classi quante sono le figure che si vogliono utilizzare. Ogni figura dovrà essere in grado di disegnarsi correttamente, dello spessore e del colore richiesti dall’utente: inoltre dovrà accettare una “lavagna” sulla quale produrre il proprio output. 2. In seguito si dovrà testare il funzionamento delle nuove classi, riutilizzando l’astrazione SimpleDrawPad, già utilizzata in precedenza. NOTA SimpleDrawPad permette di creare una finestra, ove disegnare delle linee e dei punti, impostando lo spessore ed il colore del tratto. E’ inoltre possibile nascondere la finestra e cancellarne il contenuto. NOTA Shape costruisce una generica figura memorizzando le informazioni relative al colore ed allo spessore del tratto. Progetto: La figura mostra la struttura gerarchica delle classi coinvolte nel progetto. Introduco nella gerarchia un nuovo nodo che in termini pratici sarà trasparente al cliente. Introduco l’entità poligono regolare. Così mentre Square, Pentagon, Circle ecc. erediteranno da RegularPoly Rectangle erediterà direttamente da Shape in quanto irregolare. RegularPoly.java Siccome l’astrazione RegularPoly non è richiesta dalle specifiche sarà trasparente al cliente, cioè non se ne potrà creare un oggeto. Una soluzione potrebbe risiedere nel porre il costruttore privato, ma siccome le classi figlie devono poter accedere al costruttore padre utilizzerò la parola chiave protected. protected RegularPoly(int x, int y,int radlength,int siden,float r,float g, float b, int th) Il costruttore accetta le coordinate del centro, la lunghezza del raggio del cerchio in cui è inscritto il poligono, il numero dei lati, le componenti del colore e lo spessore del tratto. L’unico metodo di RegularPoly si occupa di disegnare un poligono regolare in basi ai valori passati al costruttore e ad un oggetto SimpleDrawPad che gli fornisce una “lavagna” e le primitive di disegno. public void draw(SimpleDrawPad pad) Triangle.java Siccome Triangle è un particolare RegularPoly allora erediterà da quest’ultimo: public class Triangle extends RegularPoly La classe Triangle si occupa di disegnare, in un pad passatogli per parametro, un triangolo equilatero. Al costruttore vengono passati le coordinate del baricentro, il raggio del cerchio in cui è inscritto, le componenti del colore e lo spessore del tratto. public Triangle(int x, int y, int radius,float r,float g, float b, int th) L’unico metodo di cui è dotato si occupa di disegnare in un pad un triangolo equilatero, in base ai valori passati al costruttore. public void draw(SimpleDrawPad pad) Le altre classi che derivano da RegularPoly sono analoghe a Triangle: ciò che ho detto per il triangolo vale anche per le altre figure regolari (Circle, Ottagono, Pentagono, Square). Rectangle.java Siccome Rectangle è un poligono irregolare erediterà direttamente da Shape. public class Rectangle extends Shape La classe Rectangle si occupa di disegnare all’interno di un pad un rettangolo, le cui informazioni sono passate al costruttore, quindi definite all’atto della costruzione. Accetta le coordinate dei vertici superiore-sinistra, inferiore-destro, le componenti del colore e lo spessore del tartto. public Rectangle(int x1, int y1,int x2,int y2,float r,float g, float b, int th) L’unico metodo che implementa è draw, che si occupa di disegnare il rettangolo all’interno del pad passatogli. public void draw(SimpleDrawPad pad) TestAC.java La classe TestAC si occupa di testare le classi definite, e contiene solo il metodo main. Implementazione: Siccome gran parte dei dettagli implementativi sono già stati discussi nella prima parte mi limiterò agli aspetti che ne differiscono. RegularPoly.java RegularPoly definisce il metodo draw() quindi non è una classe astratta! RegularPoly appartiene allo stesso package di Shape, quindi è necessario inserire la riga package tools. Siccome si vuole impedire che il cliente crei un oggetto di questo tipo ho deciso di definire protected il costruttore in maniera che le classi figlie vi potessero accedere. Accetta come parametri le coordinate del centro, la lunghezza del raggio ed il numero di lati, di cui si occupa personalmente. I parametri relativi allo spessore ed al colore vengono invece passati al costruttore di Shape tramite l’invocazione di super(r,g,b,th). Solo Shape infatti sa come maneggiare questi dati. Il metodo draw si occupa di disegnare un poligono regolare all’interno del pad passatogli per parametro. I dettagli implementativi sono gli stessi relativi alla I Parte del progetto. Codice (RegularPoly.java) package tools; /** * @author Luca Gardelli * @version 1.0 * * RegularPoly can draw itself can return its current thickness, colors * (the two last are inherited by Shape) */ public class RegularPoly extends Shape { //private data storage private int xc,yc,radius,sidesNumber; /** * Default constructor * * @param xc : center coordinate * @param yc : center coordinate * @param radlenght : radius length * @param siden : sides number * @param r : red color percentage * @param g : green color percentage * @param b : blue color percentage * @param th : thickness */ protected RegularPoly(int x, int y,int radlength,int siden,float r,float g, float b, int th) { super(r,g,b,th); xc=x; yc=y; radius=radlength; sidesNumber=siden; } /** * Draw a regular poly using a pad * * @param pad : a SimpleDrawPad object */ public void draw(SimpleDrawPad pad) { double alpha=360/sidesNumber; int x0=xc; //starting x int y0=yc-radius; //starting y int x1,y1; for (int i=1;i<=sidesNumber;i++){ //rotate the point x1=(int)(xc+radius*Math.sin(i*alpha*Math.PI/180)); y1=(int)(yc-radius*Math.cos(i*alpha*Math.PI/180)); //connect the points (x0-x1,y0-y1) pad.drawLine(x0,y0,x1,y1); x0=x1;y0=y1; } //correct any error pad.drawLine(x0,y0,xc,yc-radius); } } Triangle.java Triangle fa parte dello stesso package di Shape, quindi occorre inserire la riga package tools. Il costruttore non fa nulla se non accettare i parametri di costruzione e invocare con gli stessi il costruttore padre (RegularPoly). Da notare che oltre ai parametri passati, Triangle aggiunge il numero dei lati nella chiamata al costruttore padre. Il metodo draw recupera le informazioni relative al colore e allo spessore del tratto tramite i metodi getColorXComponent (X=Red/Blue/Green) e getThickness. Quindi rende attive le impostazioni utilizzando i metodi forniti dalla classe SimpleDrawPad, setCurrentColor, setCurrentThickness. Quindi richiama il metodo draw della classe padre. Codice (Triangle.java) : package tools; /** * @author Luca Gardelli * @version 1.0 * * Triangle can draw itself can return is current thickness, colors * (inherit from RegularPoly) */ public class Triangle extends RegularPoly { /** * Default constructor - only calls parent constructor * * @param x : center coordinate * @param y : center coordinate * @param radius : radius length * @param r : red color component * @param g : green color component * @param b : blue color component * @param th : thickness */ public Triangle(int x, int y, int radius,float r,float g, float b, int th) { //calls parent constructor super(x,y,radius,3,r,g,b,th); } /** * Draw a Triangle as a RegularPoly * *@param pad : a SimpleDrawPad object */ public void draw(SimpleDrawPad pad) { float r=getColorRedComponent(); float g=getColorGreenComponent(); float b=getColorBlueComponent(); int th=getThickness(); //set color and thickness pad.setCurrentColor(r,g,b); pad.setCurrentThickness(th); //calls parent draw() super.draw(pad); } } Circle.java, Pentagon.java, Octagon.java, Square.java Il codice relativo a queste classi è identico a quello di Triangle.java con l’unica differenza nel passaggio del numero dei lati al costruttore di RegularPoly. In particolare per quanto riguarda Circle si passano un numero sufficientemente alto di lati tali da approssimare una circonferenza. Rectangle.java Siccome un rettangolo non è un poligono regolare eredita direttamente da Shape: siccome viene definito il metodo draw() Rectangle non è abstract! Anche la classe Rectangle appartiene al package tools. Il costruttore riceve tutti i parametri relativi alla costruzione: le coordinate dei vertici vengono gestite dallo stesso, mentre le altre informazioni vengono passati al costruttore della classe padre (Shape). Anche Rectangle recupera i dati relativi al colore e spessore tramite le funzioni messe a disposizione da Shape. In seguito attiva le impostazioni e disegna la figura tramite primitive linea messe a disposizione dalla classe SimpleDrawPad. Codice (Rectangle.java) : package tools; /** * @author Luca Gardelli * @version 1.0 * * Rectangle can draw itself can return is current thickness, colors * (the two last are inherited by Shape) */ public class Rectangle extends Shape { //private data storage private int xul,yul,xbr,ybr; /** * Default constructor * * @param x1 : upper left corner * @param y1 : upper left corner * @param x2 : bottom right corner * @param y2 : bottom right corner * @param r : red color component * @param g : green color component * @param b : blue color component * @param th : thickness */ public Rectangle(int x1, int y1,int x2,int y2,float r,float g, float b, int th) { super(r,g,b,th); xul=x1; yul=y1; xbr=x2; ybr=x2; } /** * Simply draw a rectangle using a pad * * @param pad : a SimpleDrawPad object */ public void draw(SimpleDrawPad pad) { float r=getColorRedComponent(); float g=getColorGreenComponent(); float b=getColorBlueComponent(); int th=getThickness(); //set color and thickness pad.setCurrentColor(r,g,b); pad.setCurrentThickness(th); pad.drawLine(xul,yul,xbr,yul); pad.drawLine(xbr,yul,xbr,ybr); pad.drawLine(xbr,ybr,xul,ybr); pad.drawLine(xul,ybr,xul,yul); } } TestAC.java La classe TestAC serve per testare le classi create: crea un array di oggetti Shape. Inizializza ogni cella con una figura diversa e le disegna all’interno del pad. Attende quattro secondi quindi termina l’esecuzione. Codice (TestAC.java) : import tools.*; /** * * @author Luca Gardelli * @version 1.0 */ public class TestAC { public static void main(String args[]) { //Build a SimpleDrawPad object SimpleDrawPad pad=new SimpleDrawPad(); //Build a Shape array and initialize it Shape shapes[]= new Shape[4]; shapes[0]=new Triangle(200,200,40,0.5f,0,1f,4); shapes[1]=new Rectangle(10,20,40,120,0,1f,0.2f,2); shapes[2]=new Circle(300,300,20,1f,0,0,1); shapes[3]=new Pentagon(40,250,30,1f,1f,0,2); //Show the pad pad.show(); //Draw each figure for(int i=0; i<4; i++){ shapes[i].draw(pad); } //Wait 4 seconds try { Thread.currentThread().sleep(4000); } catch (Exception ex){ } // Exit System.exit(0); } } Casi d’uso: L’esecuzione del programma TestAC fornisce in output la seguente figura. Questo è del tutto in accordo con il codice. Concetti acquisiti: Riuso delle astrazioni: La possibilità di riutilizzare classi già create rende il lavoro di sviluppo molto più rapido e sicuro in quanto si evita di compiere incongruenze ed errori. Organizzazione: In questo progetto si sente la necessità di organizzare logicamente le classi create. Seppure di modesta entità già la presenza di una decina di classi ne richiede la suddivisione in package. Il Java offre quindi un’opportunità per separare logicamente e fisicamente classi appartenenti allo stesso gruppo. Polimorfismo: Il Java supporta il polimorfismo. Un esempio è la classe TestAC nella quale viene creato un array di oggetti ed inizializzato con oggetti figli. Il compilatore non segnala nessun errore. La chiamata ai metodi viene risolta in tempo di esecuzione (Late Binding). Per questo il compilatore non deve sapere a priori quale metodo dovrà chiamare. Ereditarietà e classi astratte: Sicuramente il punto fondamentale di questo progetto è l’uso delle classi astratte in combinazione con il meccanismo di ereditarietà. Il tipo di procedimento adottato permette di costruire delle gerarchie di classi organizzate correttamente e facilmente espandibili. La soluzione implementata nella I parte risultava concettualmente corretta, ma di poco versatile. Ogni qualvolta si presentava la necessità di una nuova figura occorreva riscrivere la classe DrawPad: questo naturalmente è impensabile, soprattutto in progetti di grandi dimensioni. Occorre perciò adottare un approccio di tipo gerarchico. - INDEX -