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 -