Gestionale di un concessionario con interfaccia grafica in Java, costruito su una gerarchia di veicoli e un contenitore generico con tipo limitato.
Progetto realizzato come prova d'esame del modulo Java, all'interno del percorso formativo Web Developer AI presso la Steve Jobs Academy (Catania). La traccia era libera: la scelta del dominio e della struttura delle classi è mia.
Il materiale teorico su cui ho preparato l'esame è raccolto nella guida a Java che ho scritto durante il modulo.
Un concessionario vende mezzi diversi tra loro, ma tutti condividono le stesse informazioni di base: una marca, un modello, un prezzo. Quello che cambia è ciò che li rende specifici — un'auto ha un numero di porte, una moto può avere o meno il bauletto.
È il caso tipico dell'ereditarietà: invece di ripetere marca, modello e prezzo in ogni classe, li si dichiara una volta sola in una classe madre.
Vehicle è dichiarata abstract perché nella realtà non si compra un "veicolo generico": si compra un'auto o una moto. La classe madre esiste per essere ereditata, non per essere istanziata.
public abstract class Vehicle {
private String brand;
private String model;
private double price;
public Vehicle(String brand, String model, double price) {
this.brand = brand;
this.model = model;
this.price = price;
}
// ...
}| Classe | Ruolo | Campo specifico |
|---|---|---|
Vehicle |
Classe astratta madre | marca, modello, prezzo |
Car |
Sottoclasse | doorsNumber — numero di porte |
Motorcycle |
Sottoclasse | topCase — presenza del bauletto |
Parking<T extends Vehicle> |
Contenitore generico | gestisce la collezione di veicoli |
Entrambe le sottoclassi richiamano il costruttore della classe madre con super e aggiungono il proprio campo distintivo.
Parking è la parte tecnicamente più interessante del progetto:
public class Parking<T extends Vehicle> {
private ArrayList<T> vehicles = new ArrayList<>();
public void updateVehiclePriceAt(int index, double newPrice) {
if (index >= 0 && index < vehicles.size()) {
T vehicle = vehicles.get(index);
vehicle.setPrice(newPrice);
} else {
throw new IndexOutOfBoundsException("Posizione del veicolo non valida!");
}
}
// ...
}Il vincolo T extends Vehicle fa due cose insieme.
Impedisce inserimenti insensati. Un parcheggio accetta qualsiasi veicolo, ma solo veicoli. Scrivere Parking<String> produce un errore di compilazione, non un crash a runtime.
Rende possibile il codice sopra. La riga vehicle.setPrice(newPrice) compila solo perché il compilatore sa che T è un Vehicle e quindi possiede quel metodo. Senza il vincolo, con un semplice Parking<T>, quella chiamata non sarebbe consentita: il compilatore non avrebbe modo di sapere che T ha un prezzo.
Il contenitore interno è un ArrayList e non un array: la dimensione non è fissata in partenza, e aggiunte e rimozioni non richiedono di spostare manualmente gli elementi.
L'incapsulamento non è applicato solo per convenzione. Il setter del prezzo rifiuta valori insensati:
public void setPrice(double newPrice) {
if (newPrice <= 0) {
throw new IllegalArgumentException("Il prezzo deve essere maggiore di 0");
}
this.price = newPrice;
}Allo stesso modo, removeVehicle e updateVehiclePriceAt verificano che la posizione richiesta esista prima di agire, lanciando un'eccezione con un messaggio esplicito invece di lasciare che il programma fallisca in modo oscuro.
- Classe astratta —
Vehiclecome base comune non istanziabile - Ereditarietà —
extendse chiamata al costruttore madre consuper - Incapsulamento — campi privati, accesso tramite getter e setter con validazione
- Generici con tipo limitato —
<T extends Vehicle> - Collezioni —
ArrayListper una raccolta a dimensione variabile - Eccezioni —
IllegalArgumentExceptioneIndexOutOfBoundsExceptionlanciate conthrow instanceof— distinzione tra auto e moto in fase di visualizzazione
Layout a tre colonne: il form di inserimento sulla sinistra, con un menu a tendina che cambia il campo specifico in base al tipo di mezzo selezionato, e due pannelli separati sulla destra per le automobili e le motociclette in stock.
Nota sulla realizzazione: l'interfaccia grafica Swing è stata generata con l'assistenza dell'intelligenza artificiale, secondo l'indicazione esplicita del docente. L'obiettivo didattico del progetto riguardava la progettazione a oggetti, non la costruzione dell'interfaccia. La modellazione delle classi e la logica applicativa sono di mia realizzazione.
Nessuna dipendenza esterna: Swing fa parte della libreria standard.
javac *.java
java DealershipGUI
Richiede un JDK installato. Verifica con javac --version.
- Persistenza dei dati. L'elenco dei veicoli vive in memoria e si perde alla chiusura. Il salvataggio su file renderebbe il gestionale utilizzabile davvero.
- Ricerca e ordinamento. Filtrare per marca o ordinare per prezzo sono le funzioni che mancano per primo a un gestionale reale.
- Nuove tipologie di veicolo. La struttura è predisposta: aggiungere un
Truckrichiede solo una nuova sottoclasse diVehicle, senza toccareParkingné le classi esistenti. - Sostituire
instanceofcon il polimorfismo. La GUI distingue auto e moto con dei controlli di tipo. Un metodo astratto inVehicle, ridefinito da ogni sottoclasse, permetterebbe di ottenere lo stesso risultato senza chiedere all'oggetto cosa sia.
- Java — libreria standard,
java.util.ArrayList - Swing per l'interfaccia grafica
- Visual Studio Code come ambiente di sviluppo
Riccardo Mazza — @Richard-WebDev Studente Web Developer AI, Steve Jobs Academy
