O seguinte exemplo ilustra a utilização de interfaces em Java. Note-se que, além das interfaces, são também utilizadas classes abstractas, por forma a contrastar a utilização de cada conceito. O diagrama UML fornece uma panorâmica do conjunto de interfaces e classes: a amarelo estão representadas as interfaces e a verde as classes abstractas; as classes normais estão a branco.
O exemplo implementa vários conceitos, sendo os principais o de cão e o de vigilante. São definidos outros conceitos que especializam estes e outros que fornecem implementações concretas de cada um. Assim, o conceito de robot é o de um vigilante automático e o de cão de guarda um vigilante canino.
São utilizadas as seguintes interfaces e classes: Cão, Vigilante, CãoDeGuarda, CãoPastor, Chihuahua, Robot, XP, XP2018.
A interface Cão define as assinaturas dos métodos a que qualquer classe que implemente um cão deve saber responder.
interface Cão {
void ladrar();
int nPatas();
}
Embora nada seja expresso na interface, além da assinatura, assume-se que a semântica a associar a cada método é a seguinte:
As classes que implementem a interface, embora não sejam obrigadas a implementar esta semântica, têm todo o interesse em fazê-lo.
Por seu turno, a interface Vigilante define as assinaturas dos métodos a que uma entidade "vigilante" deve saber responder.
interface Vigilante {
boolean háIntrusos();
void soarAlarme();
}
A semântica a associar pelas implementações é a seguinte:
A interface Robot é uma especialização de Vigilante: é um vigilante robotizado que sabe avisar e destruir intrusos.
interface Robot extends Vigilante {
void avisarIntrusos();
void destruirIntrusos();
}
As implementações da interface Robot, além do que já se disse para a interface Vigilante, devem fornecer a seguinte semântica por método:
A interface CãoDeGuarda, de modo análogo a Robot define a assinatura das implementações de um cão de guarda, i.e., um cão vigilante.
interface CãoDeGuarda extends Cão, Vigilante {
void morder();
}
Note-se a utilização de herança múltipla.
A primeira classe deste exemplo é CãoPastor. Esta classe implementa parte da interface de um cão de guarda e deixa para as suas subclasses a especificidade associada ao método ladrar(). Embora abstracta, esta classe é uma implementação (ainda que parcial) da interface.
<java5>
public abstract class CãoPastor implements CãoDeGuarda { public final static int N_PATAS = 4; // métodos privados private void fecharBoca() { /* qualquer coisa */ } private boolean háPredadores() { /* qualquer coisa */ return true; } // interface CãoDeGuarda public void morder() { fecharBoca(); } // inteface Cão public int nPatas() { return N_PATAS; } public abstract void ladrar(); // interface Vigilante public void soarAlarme() { ladrar(); } public boolean háIntrusos() { return háPredadores(); } }
</java5>
Um exemplo de uma classe (não abstracta, i.e., implementa ladrar()) derivada de CãoDeGuarda é a que se segue. Esta classe apenas necessita de implementar o método ladrar() para ficar completa.
<java5>
public class Chihuahua extends CãoPastor { public void ladrar() { System.out.println("guau, guau"); } }
</java5>
Supõe-se que a classe XP existe independentemente das outras descritas até aqui (foi, por exemplo, definida para outro fim). Supõe-se, contudo, que contém funcionalidade útil para uma possível implementação de um robot, i.e., para uma classe que implemente a interface Robot.
<java5>
public class XP { public void reboot() { System.out.println("See ya!"); } public void shutdown() { System.out.println("Bye!"); } public void crash() { System.out.println("Nooo! Argh!!!"); } public boolean háIntrusos() { return false; } // detector de vírus }
</java5>
Note-se a coincidência do método háIntrusos(): existe na classe XP e na interface Vigilante (da qual Robot herda parte da sua especificação). É necessário garantir que a semântica pretendida é a que o método realmente fornece.
Esta é uma implementação de Robot que reutiliza XP.
<java5>
public class XP2018 extends XP implements Robot { // interface Robot public void avisarIntrusos() { System.out.println("Isto é o último aviso!"); } public void destruirIntrusos() { System.out.println("Eu avisei..."); } // interface Vigilante public void soarAlarme() { System.out.println("AAAARGH"); } //public boolean háIntrusos() { return true; } // herdado de XP... }
</java5>
Note-se que o método háIntrusos() é implementado pela superclasse (XP). A consideração deste aspecto é de importância crucial, pois pode introduzir erros se o comportamento não for o desejado (o que provavelmente acontece: em XP, os intrusos são -- por hipótese -- virus e em XP2018, uma implementação de um vigilante robotizado, a semântica é outra).
Considere-se a seguinte classe que exercita os conceitos anteriores: <java5>
public class Teste { public static void main(String[] args) { Cão c = new Chihuahua(); Vigilante v = new Chihuahua(); CãoPastor p = new Chihuahua(); Robot r = new XP2018(); XP x = new XP(); XP y = new XP2018(); c.ladrar(); v.soarAlarme(); ((Chihuahua)v).ladrar(); p.soarAlarme(); r.avisarIntrusos(); r.soarAlarme(); x.reboot(); y.crash(); ((XP2018)y).soarAlarme(); } }
</java5>
O resultado da aplicação acima é o seguinte:
$ java Teste guau, guau guau, guau guau, guau guau, guau Isto é o último aviso! AAAARGH See ya! Nooo! Argh!!! AAAARGH