JAVA – Classes Abstractas ATAI 1 O conceito de Classe Abstracta É um conceito aplicável à reutilização => concepção de aplicações genéricas e extensíveis Definição completa de Classe A classe define completamente a estrutura e o código das suas instâncias (variáveis e métodos de instância) Definição incompleta de Classe A classe não define completamente a estrutura e o código das suas instâncias Alguns ou todos os métodos podem ser apresentados sintacticamente (nome, parâmetros de entrada, tipo de resultado) mas não possuírem corpo ou código (métodos abstractos) A classe não pode criar instâncias 2 Definição Classes Abstractas Todas as classes nas quais pelo menos um método de instância não se encontra implementado, mas apenas declarado (método abstracto) Uma classe abstracta não pode criar instâncias O mecanismo de herança mantém-se aplicável a classes abstractas Declaração: abstract public abstract class Figura { //metodos de instancia abstractos public abstract double area(); public abstract double perimetro(); } Circulo Figura Rectângulo Triângulo 3 Aplicação => Desenvolvimento de aplicações genéricas e extensíveis Figura Regra: o mecanismo de herança mantém-se aplicável a classes abstractas Circulo Rectângulo Triângulo Implicações de termos classes abstractas na hierarquia de classes qualquer subclasse de uma classe abstracta herda automaticamente todos os métodos da classe abstracta, estejam implementados ou sejam abstractos qualquer subclasse de uma classe abstracta terá de implementar todos os métodos abtractos herdados da sua superclasse (sem excepção) para que possa ser uma classe de implementação concreta, i.e., para que possa ter instâncias uma classe abstracta delega nas suas subclasses a responsabilidade pela implementação dos seus métodos abstractos, facilitando o aparecimento de diferentes implementações dos mesmos métodos nas suas subclasses 4 Aplicação Ex: Classe 100% abstracta o mecanismo de herança garante que todas as suas subclasses vão herdar o mesmo protocolo ou API, podendo no entanto definir as suas extensões todas as subclasses da classe abstracta responderão ao mesmo protocolo, ou seja, “falam a mesma linguagem” normalização de vocabulário para as subclasses existentes e para as futuras subclasses o polimorfismo da linguagem JAVA garantirá a correcta execução desta “linguagem comum” classe 100% abstracta pode ser vista como uma assinatura (especificação meramente sintáctica) 5 Aplicação Em resumo, as classes abstractas: 1. 2. Permitem escrever especificações sintácticas para as quais múltiplas implementações são possíveis de momento ou de futuro Permitem normalizar a “linguagem” (API) a partir de certos pontos da hierarquia 3. Permitem introduzir flexibilidade e generalidade nas classes criadas 4. Permitem tirar todo o partido do polimorfismo (via substitutividade) 5. Permitem uma metodologia de desenvolvimento de SW de refinamento progressivo por especialização 6 Aplicação Em resumo, as classes abstractas: 6. Ocupam normalmente os níveis mais elevados das hierarquias 7. Devem declarar o maior número possível de métodos abstractos, pois passarão a constituir a linguagem comum (API) das suas subclasses. 8. Colocar variáveis ou código concreto numa classe abstracta em geral não é aconselhável em JAVA pois todas as suas subclasses presentes e futuras irão herdar tais variáveis e métodos 9. O número de métodos abstractos dependerá da análise de requisitos do problema. poderá no entanto haver situações em que colocar o máximo de funcionalidade numa classe abstracta seja vantajoso Em geral, as classes abstractas em JAVA devem ser 100% abstractas 7 Caso de Estudo 8 Classe Figura… A classe Figura pode ter atributos que sejam comuns a todas as classes (ex. coordenadas do objecto) A classe Figura declara e fornece definições para métodos que são independentes do tipo real do objecto, como por exemplo: o método posicao, que poderia ser um método final O método area deve ser declarado abstract porque é difícil calcular a área de um objecto abstracto Um objecto Figura não pode ser criado, apenas os objectos derivados podem Uma variável Figura pode referenciar qualquer objecto concreto derivado, tal como Circulo ou Rectangulo Figura a, b; a = new Circulo( 3.0 ); b = new Figura( "circulo" ); // correcto // errado 9 Classe Figura Um objecto de uma classe abstracta nunca pode ser criado. É possível fornecer um construtor que pode ser chamado pela classe derivada, para iniciar os membros privados. A classe abstracta Figura poderia ser: abstract class Figura { private String nome; public abstract double area( ); public Figura( String nomeFigura ) { nome = nomeFigura; } public alterarNomeFigura( String nomeFigura ) { nome = nomeFigura; } final public boolean menorQue( Figura rhs ) { return this.area( ) < rhs.area( ); } final public String toString( ) { return "Area do " + nome + ": " + area( ); } } 10 Expandindo a Classe Figura Lê N tipos de figuras: Círculos Quadrados Rectângulos Para implementar estas classes é necessário: Fornecer um novo construtor Escrever novas definições para os métodos herdados cujas implementações não servem Escrever uma definição para cada método abstracto Escrever métodos adicionais, se necessários 11 Classe Circulo public class Circulo extends Figura { private static final double PI = 3.14159265358979323; private double raio; public Circulo( double r ) { super( "circulo" ); raio = r; } public double area( ) { return PI * raio * raio; } } 12 Classe Rectângulo e Quadrado public class Retangulo extends Figura { private double altura; private double base; public Retangulo( double alt, double bas ) { super( "retângulo" ); altura = alt; base = bas; } public double area( ) { return altura * base; } } public class Quadrado extends Retangulo { public Quadrado( double lado ) { super( lado, lado ); alterarNomeFigura (“quadrado" ); } } 13 Classe TesteFigura… import java.io.*; class TestaFigura { private static BufferedReader ent; private static Figura leFigura( ) //implementado no slide seguinte public static void main( String [ ] args ) { try { // Obtém número de figuras System.out.println( "Entre com o número de " + "figuras: " ); ent = new BufferedReader( new InputStreamReader( System.in ) ); int numFiguras = Integer.parseInt( ent.readLine( ) ); // Le as Figura [ ] for( int i array[ i figuras array = new Figura[ numFiguras ]; = 0; i < numFiguras; i++ ) ] = leFigura(); System.out.println( “impressao:" ); for( int i = 0; i < numFiguras; i++ ) System.out.println( array[ i ].toString() ); } catch( Exception e ) { System.out.println( e ); } } 14 Classe TesteFigura… private static Figura leFigura( ) { double raio; double altura; double base; String umaLinha; try { System.out.println( “Tipo da figura:"); do { umaLinha = ent.readLine( ); } while( umaLinha.length( ) == 0 ); switch( umaLinha.charAt( 0 ) ) { case 'c': System.out.println( “Circulo-introduza o Raio: " ); raio = Double.valueOf( ent.readLine( ) ).doubleValue( ); return new Circulo( raio ); case 'q': System.out.println( " Quadrado-introduza o lado: " ); altura = Double.valueOf( ent.readLine( ) ).doubleValue( ); return new Quadrado( altura ); 15 Classe TesteFigura case 'r': System.out.println( "Entre com a altura " + "e a largura " + "em linha separadas: " ); altura = Double.valueOf( ent.readLine( ) ).doubleValue( ); base = Double.valueOf( ent.readLine( ) ).doubleValue( ); return new Retangulo( altura, base ); default: System.err.println( “Introduza c, r, ou q); return new Circulo( 0 ); } } catch( IOException e ) { System.err.println( e ); return new Circulo( 0 ); } } 16