Anonymous_User ha scritto:
Le classi le ho sempre realizzate più o meno sul modello che ti ho mostrato, e nonostante non sia il modo più adatto, non ho mai riscontrato particolari problemi, credo sia più una questione di ordine e coerenza nella scrittura del codice
No, non è quello il punto. Per programmare in Java "ad oggetti" ci sono tutta una serie di principi e convenzioni da conoscere ed applicare.
E giusto per darti una idea ....
Facciamo una classe Persona:
import java.io.Serializable;
public class Persona implements Serializable {
private static final long serialVersionUID = 1L;
private String nome;
private int annoNascita;
public Persona(String nome, int annoNascita) {
this.nome = nome;
this.annoNascita = annoNascita;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public int getAnnoNascita() {
return annoNascita;
}
public void setAnnoNascita(int annoNascita) {
this.annoNascita = annoNascita;
}
@Override
public String toString() {
return "Persona[nome=" + nome + ", annoNascita=" + annoNascita + "]";
}
}
I campi sono rigorosamente
private, per il buon principio di "incapsulamento". E ci sono i metodi detti "accessori" (getter/setter) che rispettano le specifiche JavaBeans. C'è un costruttore esplicito ma solo per comodità nella costruzione. C'è un toString() che dà una forma che è quella tipica "tecnica" che si usa per debugging. Ma si potrebbe formare la stringa diversamente.
Ci potrebbe essere dell'altro, es. i metodi equals(Object) e hashCode(). Sai a cosa servono? E quale è il "contratto" che deve esistere tra questi due? Anche questi sono concetti fondamentali
da sapere.
Ma la cosa importante: NON c'è input dall'utente, né letture/scritture su file.
Il serialVersionUID non è fondamentale, è solo un "proforma" per la serializzazione e per non avere noiosi warning in un IDE.
Poi facciamo una classe che rappresenta un insieme di persone:
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ElencoPersone implements Serializable, Iterable<Persona> {
private static final long serialVersionUID = 1L;
private List<Persona> persone = new ArrayList<>();
public void aggiungiPersona(Persona persona) {
persone.add(persona);
}
@Override
public Iterator<Persona> iterator() {
return persone.iterator();
}
}
Qui si potrebbero mettere altri metodi (es. "dammi la persona all'indice x", "dammi il numero di persone", ecc...). Non sono importanti per ora. La implementazione di Iterable è solo per rendere un oggetto ElencoPersone "iterabile", cioè scorribile, con il costrutto
for-each di Java 5+ (vedi nel main() sotto).
Anche qui NON c'è (non va messo) input dall'utente e preferibilmente/possibilmente nemmeno I/O su file.
Poi facciamo una classe che è dedicata proprio al I/O su file di un elenco di persone:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class FileElencoPersone {
private File file;
public FileElencoPersone(File file) {
this.file = file;
}
public void scrivi(ElencoPersone elencoPersone) throws IOException {
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(fos);
oos.writeObject(elencoPersone);
} finally {
if (oos != null) {
oos.close();
} else {
fos.close();
}
}
}
public ElencoPersone leggi() throws IOException, ClassNotFoundException {
FileInputStream fis = new FileInputStream(file);
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(fis);
return (ElencoPersone) ois.readObject();
} finally {
if (ois != null) {
ois.close();
} else {
fis.close();
}
}
}
}
Un oggetto FileElencoPersone incapsula solo un oggetto File, che non è nulla di particolare e non richiede alcuna attenzione particolare. E nota come leggi() e scrivi() siano molti simili e soprattutto "simmetrici". E quello è il modo corretto di trattare le eccezioni e in particolare i close() da fare
sempre in ogni caso.
Nota: da Java 7 si può sfruttare il costrutto
try-with-resource, che permetterebbe di abbreviare molto i leggi/scrivi. Non l'ho applicato solo perché probabilmente non lo conosci. Ma non è importante.
E per finire un semplice main() di prova:
import java.io.File;
public class MainProva {
public static void main(String[] args) {
try {
FileElencoPersone fileElencoPersone = new FileElencoPersone(new File("persone.dat"));
ElencoPersone elencoPersone = new ElencoPersone();
elencoPersone.aggiungiPersona(new Persona("Mario", 1956));
elencoPersone.aggiungiPersona(new Persona("Roberto", 1977));
fileElencoPersone.scrivi(elencoPersone);
// ora rileggo da file ...
ElencoPersone elencoPersone2 = fileElencoPersone.leggi();
for (Persona persona : elencoPersone2) {
System.out.println(persona);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Non ho fatto (per semplicità/brevità) interazioni con l'utente. Ma nota come sia tutto "pulito", ben scritto, con le varie responsabilità ben separate e distribuite tra le varie classi. Nessuna classe fa "troppe" cose e nessuna ripete cose fatte da altre.
Questo è il modo di affrontare la programmazione ad oggetti in Java.