Java Básico Classes Abstratas e Interfaces Marco Antonio, Arquiteto de Software – TJDF [email protected] Atualizado em Novembro/2008
Apr 17, 2015
Java Básico
Classes Abstratas e Interfaces
Marco Antonio,
Arquiteto de Software – TJDF
[email protected] em Novembro/2008
Classe abstrata
Recurso avançado da OO
Não pode ser instanciada
Deve ser instanciada através de uma subclasse concreta
Permite modelar com mais precisão as regras de negócio
Refinamento do projeto
O programador fica obrigado a utilizar as regras definidas pelo projetista
Pode ter a implementação para os métodos
Interface
Funciona como um contrato
Não pode ser instanciada
Pode ser instanciada através de uma classe que a implemente
Obriga o programador a usar os métodos já definidos
Não tem implementação, apenas a assinatura dos métodos
Muito útil para diminuir o acoplamento entre os vários módulos do sistema
Classe abstrata x Interface
Não existe uma regra geral que defina quando usar classes abstratas ou interfaces
• O nível de refinamento deve ser definido antes da implementação, o que diminui o risco de entrar num ciclo de refinamentos sem fim
Dica
Quando haja a possibilidade de reutilização de código, prefira classe abstrata
Se o código reaproveitado é muito pequeno, talvez seja mais interessante uma interface
Exemplo de classe abstrata
Vamos utilizar a classe Musico para ilustrar o conceito de classe abstrata
Baterista, Guitarrista e Baixista são nossas outras classes do modelo
Analise o relacionamento entre elas
Musico
package com.javabasico.classesabstratas;
public abstract class Musico {
public abstract String getNomeDoInstrumento();
public void afinarInstrumento() {
System.out.println("Estou afinando o/a " + getNomeDoInstrumento());
}
}
Baixista
package com.javabasico.classesabstratas;
public class Baixista extends Musico {
public String getNomeDoInstrumento() {
return "Baixo";
}
}
Guitarrista
package com.javabasico.classesabstratas;
public class Guitarrista extends Musico {
public String getNomeDoInstrumento() {
return "Guitarra";
}
}
Baterista
package com.javabasico.classesabstratas;
public class Baterista extends Musico {
public String getNomeDoInstrumento() {
return "Bateria";
}
}
TesteDoMusico
package com.javabasico.classesabstratas;
public class TesteDoMusico {
public static void main(String[] args) {
Musico baixista = new Baixista();
baixista.afinarInstrumento();
Musico batera = new Baterista();
batera.afinarInstrumento();
Musico guitarrista = new Guitarrista();
guitarrista.afinarInstrumento();
}
}
Exemplo de interface
• Vamos utilizar a interface Veiculo no nosso exemplo
• Além desta, também teremos Carro, Moto e Caminhao
Veiculo
package com.javabasico.interfaces;
public interface Veiculo {
public int getQuantidadeDePneus();
public boolean isVeiculoDePasseio();
public int getPotencia();
}
Carro
package com.javabasico.interfaces;
public class Carro implements Veiculo {
public int getQuantidadeDePneus() {
return 4;
}
public boolean isVeiculoDePasseio() {
return true;
}
public int getPotencia() {
return 80;
}
}
Moto
package com.javabasico.interfaces;
public class Moto implements Veiculo{
public int getQuantidadeDePneus() {
return 2;
}
public boolean isVeiculoDePasseio() {
return true;
}
public int getPotencia() {
return 30;
}
}
Caminhao
package com.javabasico.interfaces;
public class Caminhao implements Veiculo {
public int getQuantidadeDePneus() {
return 6;
}
public boolean isVeiculoDePasseio() {
return false;
}
public int getPotencia() {
return 130;
}
}
TesteDoVeiculo
package com.javabasico.interfaces;
public class TesteDoVeiculo {
public static void main(String[] args) {
Veiculo minhaMoto = new Veiculo();
}
}
Qual o problema?
Qual o problema da classe de teste?• Simples: uma interface não pode ser instanciada
– new Veiculo();• Não existe, no modelo anterior, um objeto do tipo Veiculo (o veículo é apenas conceitual)
• Existem apenas Carros, Motos e Caminhoes• Toda interface deve ter uma classe que a implemente, caso contrário, não faz sentido esse tipo de refinamento
TesteDoVeiculopackage com.javabasico.interfaces;
public class TesteDoVeiculo {
public static void main(String[] args) {
Veiculo minhaMoto = new Moto();
System.out.println("Quantidade de cavalos da moto:" + minhaMoto.getPotencia());
Veiculo meuCarro = new Carro();
System.out.println("Quantidade de pneus do carro: " + meuCarro.getQuantidadeDePneus());
Veiculo meuCaminhao = new Caminhao();
System.out.println("O caminhão é veículo de passeio? " + meuCaminhao.isVeiculoDePasseio());
}
}
Exemplo Web
• Vamos imaginar a seguinte hierarquia de classes:– ControleHTML
• CaixaDeTexto• CaixaDeChecagem• Outros componentes HTML
• O ControleHTML terá os atributos comuns a todos os controles web (nome, valor) e deverá ser definido como abstract, porque o método getCodigoHTML não tem implementação.
• No momento de gerar a página HTML iremos instanciar o componente concreto (caixas de texto, comboboxes, caixas de checagem, botoes, etc).
• Para cada componente, teremos uma saída diferente para o método getCodigoHTML.
ControleHTMLpackage com.javabasico.classesabstratas;
public abstract class ControleHTML {
private String nome;
private String valor;
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
public String getValor() {
return valor;
}
public void setValor(String valor) {
this.valor = valor;
}
public abstract String getCodigoHTML();
}
CaixaDeChecagem
package com.javabasico.classesabstratas;
public class CaixaDeChecagem extends ControleHTML {
public String getCodigoHTML() {
StringBuilder html = new StringBuilder();
html.append("<input type=\"checkbox\"");
html.append("name=");
html.append(getNome());
html.append("\"value=\"");
html.append(getValor());
html.append("\">");
return html.toString();
}
}
CaixaDeTexto
package com.javabasico.classesabstratas;
public class CaixaDeTexto extends ControleHTML { public String getCodigoHTML() { StringBuilder html = new StringBuilder(); html.append("<input type=\"text\""); html.append("name=\""); html.append(getNome()); html.append("\" value=\""); html.append(getValor()); html.append("\" >"); return html.toString(); }}
PaginaWeb
package com.javabasico.classesabstratas;
public class PaginaWeb { public static void main(String[] args) { ControleHTML caixaDeTexto = new CaixaDeTexto(); caixaDeTexto.setNome("txtNome"); caixaDeTexto.setValor("Marco"); ControleHTML caixaDeChecagem = new CaixaDeChecagem(); caixaDeChecagem.setNome("chkUsuarioCadastrado"); caixaDeChecagem.setValor("1"); System.out.println(caixaDeTexto.getCodigoHTML()); System.out.println(caixaDeChecagem.getCodigoHTML()); }}
Exemplo com interfaces
• No próximo exemplo teremos as formas geométricas conforme a hierarquia:– FormaGeometrica
• Triangulo• Quadrado• Retangulo• Etc...
• A interface principal terá os métodos desenhar e apagar, claro, sem a implementação, que será feita nas classes a seguir.
FormaGeometrica
package com.javabasico.interfaces;
public interface FormaGeometrica {
public void desenhar();
public void apagar();
}
Triangulo
package com.javabasico.interfaces;
public class Triangulo implements FormaGeometrica {
public void apagar() {
System.out.println("Estou apagando o triângulo...");
}
public void desenhar() {
System.out.println("Estou desenhando um triângulo...");
}
}
Quadrado
package com.javabasico.interfaces;
public class Quadrado implements FormaGeometrica {
public void apagar() {
System.out.println("Estou apagando o quadrado.");
}
public void desenhar() {
System.out.println("Estou desenhando um quadrado.");
}
}
TesteFormasGeometricas
package com.javabasico.interfaces;
public class TesteFormasGeometricas { public static void main(String[] args) { FormaGeometrica forma = new Triangulo(); forma.desenhar(); forma.apagar(); }}
Ligação dinâmica
• Devemos observar que criamos um objeto do tipo FormaGeometrica e que dinamicamente a linguagem trocou para a classe Triangulo.
• Esse comportamento é verificado nas interfaces e nas classes.
TesteFormasGeometricas
package com.javabasico.interfaces;
public class TesteFormasGeometricas { public static void main(String[] args) { FormaGeometrica forma = new Triangulo(); forma.desenhar(); forma.apagar(); // forma = new Quadrado(); forma.desenhar(); forma.apagar(); }}
Sua vez
• Crie mais duas formas geométicas e teste tudo na nossa classe.
Curiosidades
• O mesmo objeto (forma) teve dois comportamentos diferentes, executando métodos em classes diferentes.
• No próximo exemplo teremos mais uma curiosidade, passando uma interface como parâmetro.
• O SoftwareGrafico irá aceitar somente implementações de FormaGeometrica.
• Para testar, crie a classe Elipse com os mesmos métodos da FormaGeometrica, mas não implemente a interface. Tente passá-la como parâmetro. O que acontece?
SoftwareGrafico
package com.javabasico.interfaces;
public class SoftwareGrafico { public void adicionarForma(FormaGeometrica forma) { forma.desenhar(); }
public void removerForma(FormaGeometrica forma) { forma.apagar(); }}
TesteSoftwareGrafico
package com.javabasico.interfaces;
public class TesteSoftwareGrafico {
public static void main(String[] args) {
SoftwareGrafico photoshop = new SoftwareGrafico();
Quadrado umQuadrado = new Quadrado();
photoshop.adicionarForma(umQuadrado);
//
Triangulo umTriangulo = new Triangulo();
photoshop.adicionarForma(umTriangulo);
//
photoshop.removerForma(umTriangulo);
photoshop.removerForma(umQuadrado);
}
}
Dúvidas?
Impressora
package com.javabasico.classesabstratas;
public interface Impressora {
void imprimir();
void imprimir(String texto);
}
Lexmark
package com.javabasico.classesabstratas;
public class Lexmark implements Impressora {
@Override
public void imprimir() {
System.out.println("Estou imprimindo na Lexmark...");
}
@Override
public void imprimir(String texto) {
System.out.println("Estou imprimindo o texto: " + texto + "na Lexmark.");
}
}
Teste
package com.javabasico.classesabstratas;
public class TesteDaImpressora {
public static void main(String args[]) {
Impressora l = new Lexmark();
l.imprimir();
l.imprimir("Alguma coisa");
}
}
Classes Anônimas
package com.javabasico.classesabstratas;
public class TesteImpressoraAnonima {
public static void main(String[] args) {
Impressora i = new Impressora() {
@Override
public void imprimir() {
System.out.println("Imprimindo pela classe anonima");
}
@Override
public void imprimir(String texto) {
System.out.println("Classe anonima: " + texto);
}
};
i.imprimir();
i.imprimir("Algum texto");
}
}
Exercício
• Cria uma classe para representar as peças de um veículo. Essa deverá ser uma classe genérica e abstrata (ou interface).
• Em seguida crie as peças, que serão subclasses (porta, vidro, lanterna, retrovisor).
• Por fim, crie uma classe de teste e monte um carro com essas peças.