Diciamo che avere un'interfaccia per poi avere una sola classe che la implementa è decisamente inutile. Le interfacce servono per definire il comportamento di una categoria di classi. Nel tuo esempio, l'interfaccia Animale, può essere implementata da Gatto, Cane, Serpente, ecc... La classe Animale definisce quelle caratteristiche che un animale deve avere, le classi Gatto, Cane e Serpente le implementano.
A cosa serve tutto questo? Innanzitutto a dire, vuoi fare una classe che implementa Animale, beh, deve avere quei metodi. In secondo luogo serve a fare una cosa di questo genere.
Animale animale;
if(input == "gatto") animale = new Gatto();
if(input == "pesce") animale = new Pesce();
In questo moto tu hai un oggetto o Gatto o Pesce, ma che viene visto come un oggetto Animale generico. Cioè puoi richiamare solo i metodi definiti nell'interfaccia (a meno di non castare).
Se tu vuoi un gatto, devi instanziare un oggetto Gatto, non un oggetto Animale.
Cerco di fare un esempio più pratico.
Hai un interfaccia Persona, che ha due attributi ragioneSociale e codiceFiscale e i get e i set dei due attributi. Tu implementi due classi, PersonaFisica e PersonaGiuridica che implementano i metodi dell'interfaccia, il metodo setCodiceFiscale di PersonaFisica e quello di PersonaGiuridica sono diversi, perché sono diversi i codiciFiscali. Stesso discorso per ragioneSociale (supponi di avere un meccanismo che aggiunga la sigla srl, snc o spa)
Ora tu supponi di voler stilare un elenco delle ragioniSociali di tutte le persone che hai nel database, indifferentemente da se esse siano Persone Giuridiche o Persone Fisiche.
Fai una lista e ad ogni elemento che trovi nell'array appendi alla lista
Persona p;
se (persona è personaFisica) {
p = new PersonaFisica();
}
else{
p = new PersonaGiuridica();
}
lista.add(p);
poi stampi tutte le ragioniSociali degli oggetti contenuti nella lista, che per te saranno Persone, indipendentemente da se siano Fisiche o Giuridiche.
Se invece ti interessano solo le PersoneFisiche, allora non ha senso sfruttare l'interfaccia, ma sfrutti la classe implementata con tutto ciò che implementa. Se devi creare una nuova persona e salvarla nel database, allora non sfrutti l'interfaccia, ma la classe implementata
se vuoi creare una PersonaFisica{
PersonaFisica persona = new PersonaFisica(...);
//set
database.save(persona);
}
altrimenti{
PersonaGiuridica persona = new PersonaGiuridica(...);
//set
database.save(persona);
}
spero di essere stato chiaro. L'Interfaccia serve per dire: tutti gli oggetti che implementano questa interfaccia possono funzionare in questo modo. Quindi tu puoi sfruttare quegli oggetti come se fossere un oggetto di questa classe, ma non sono comunque oggetti di questa classe.
Un altro esempio, che a volte capita di utilizzare. Hai una LinkedList e un ArrayList, vuoi creare un metodo che possa leggerle indiffferentemente da quale delle due liste vuoi leggere.
Prendi come parametro una List generica
public void readList (List l){
Iterator i = l.iterator();
while(i.hasNext()){
ecc...
}
}
List è un'interfaccia e anche Iterator è un'interfaccia. Tu puoi passare una LinkedList o un ArrayList al metodo readList, ma per il metodo quelle sono List e basta. Il metodo legge la Lista qualsiasi List essa sia (un Vector, uno Stack, un ArrayList ecc..)
Ma se tu hai una LinkedList e basta e vuoi un metodo che legga quella LinkedList, allora non usi List, ma LinkedList con tutte le sue caratteristiche.