JAVA Professor: Bruno Toledo Aplicando Orientação a Objetos com Java Abstração em Programação JAVA é Orientado a Objetos Até é possível usar Java sem OO, mas... Perderá todas as vantagens que o paradigma proporciona; Dificilmente irá além de programas simples; ou terá “monstros macarrônicos”; Será difícil entender outros programas; O código ficará difícil de ler, manutenir e reutilizar; Estará perdendo tempo. Use outra linguagem. Abstração em Programação Por trás dos conceitos da orientação a objetos, está a preocupação com: Aproximação a situações do “mundo real”; Reutilização de código; Aplicação de uma mesma solução a diversas situações diferentes. Logo, para fazer bom uso de Java é preciso conhecer bem os conceitos da Orientação a Objetos. Motivos que Influenciaram Avanços na tecnologia de arquiteturas de computadores, suportando sofisticados ambientes de programação e interfaces homem-máquina. Avanços na área de linguagens de programação como modularização, ocultamento de informação, etc. Crise do Software: termo utilizado para descrever problemas associados ao modo como o software é desenvolvido, como é feita a manutenção e como acompanhar a demanda por mais software (PRESSMAN, 1995). Vantagens da Tecnologia de Objetos Facilita a reutilização de código; Os modelos refletem o mundo real de maneira mais aproximada: Descrevem de maneira mais precisa os dados; A decomposição é baseada em um particionamento natural; e Mais fáceis de entender e manter. Pequenas mudanças nos requisitos não implicam em alterações massivas no sistema em desenvolvimento; Implementação de Tipos Abstratos de Dados. O que é a Orientação a Objetos É um paradigma para o desenvolvimento de software que baseia-se na utilização de componentes individuais (objetos) que colaboram para construir sistemas mais complexos. A colaboração entre os objetos é feita através do envio de mensagens. Um paradigma é um conjunto de regras que estabelecem fronteiras e descrevem como resolver problemas dentro desta fronteira. Um paradigma ajuda-nos a organizar a e coordenar a maneira como olhamos o mundo. “Preconceitos” sobre Orientação a Objetos A orientação a objetos não é uma metodologia para o desenvolvimento de interfaces gráficas amigáveis, ou seja, o paradigma de objetos não está necessariamente relacionada a programação visual; A orientação a objetos não elimina a necessidade de implementar os sistemas, e nem está relacionadas apenas a fase de implementação; A orientação a objetos não garante a reutilização, ela oferece mecanismos para que isso ocorra, mas sempre será função do desenvolvedor garantir isso. Desenvolvimento Orientado a Objetos Análise Orientada a Objetos: É o processo de construção de modelos do domínio do problema, identificando e especificando um conjunto de objetos que interagem e comportam-se conforme os requisitos estabelecidos para o sistema. Projeto Orientado a Objetos: é o processo de geração de uma especificação detalhada do software a ser desenvolvido, de tal forma que esta especificação possa levar a direta implementação no ambiente alvo. Desenvolvimento Orientado a Objetos Programação Orientada a Objetos: é um modelo de programação que baseia-se em conceitos como classes, objetos, herança, etc. Seu objetivo é a resolução de problemas baseada na identificação de objetos e o processamento requerido por estes objetos, e então na criação de simulações destes objetos. A programação é obtida através da definição de classes e criação de hierarquias, nas quais propriedades comuns são transmitidas das superclasses para as subclasses através do mecanismo de herança. Objetos destas classes são instanciados tal que a execução do programa é vista como um conjunto de objetos relacionados que se comunicam enviando mensagens uns para os outros. Orientação a Objetos Objetivos: Diminuir a distância entre o mundo real e o modelo abstrato de solução. “O mundo é composto por objetos”. Trabalhar com noções intuitivas, retardando a implementação. Um sistema construído usando um método Orientado a Objetos é aquele cujos componentes são partes encapsuladas de dados e funções, que podem herdar atributos e comportamento de outros componentes da mesma natureza, e cujos componentes comunicam-se entre si por meio de mensagens (Yourdon, 1994). Orientação a Objetos Objetos Objetos são instâncias das classes que os definem. Um objeto deve ser declarado e inicializado antes de ser usado. Palavra chave new Objetos Declarando um objeto de uma classe em Java Se lembrar bem, você já declarou objetos de classe em nosso curso de Java. Mais especificamente, declarou objetos da classe Scanner, várias vezes. Objetos Agora, vamos fazer o mesmo com nossa classe Aluno. Vamos criar um objeto, um aluno da classe “Aluno”. Aluno joaozinho = new Aluno(); Aluno maria = new Aluno(); Aluno programador = new Aluno(); Pronto, criamos três objetos do tipo Aluno. Poderíamos ter feito como dito nos slides anteriores: Aluno joaozinho; joaozinho = new Aluno(); Objetos O new Aluno() é o que cria o objeto. E atribuímos ele à variável joaozinho. Essa variável, porém, não é um objeto. Ela contém uma referência ao objeto. É como se ela apontasse, como se tivesse o endereço da localização do objeto. Então, sempre que mudamos essa variável, estamos mudando diretamente o objeto. Objetos Porém, fica pouco usual dizer ‘declare uma referência ao objeto Aluno’. No dia-a-dia, simplesmente dizemos: criamos um objeto do tipo Aluno. Mas na verdade essas variáveis não são objetos, e sim referências a objetos. O importante é saber disso. Qualquer coisa, métodos ou dados que colocarmos na classe "Aluno", fará parte dos objetos “joaozinho”, “maria” e “programador”. Objetos Objetos Objetos Como descrever os objetos no mundo computacional? Temos de mapear os objetos reais em objetos computacionais e escrever programas que dão vida a estes objetos em um sistema computacional. Objetos (computacionais) são caracterizados por atributos e métodos: • Atributos são as propriedades de um objeto; • Métodos são as ações que um objeto pode realizar; - a execução de um método muda os valores dos atributos do objeto responsável pela execução; - neste caso dizemos que o objeto mudou de estado; • Objetos são modelados através de classes. Classes Classes definem os dados e as funções (métodos) que estarão disponíveis para os objetos. public class nomeClasse { // atributos e métodos... } Java: cada classe fica em um arquivo separado com o mesmo nome da classe (nomeClasse.java) Classes Classes x Objetos Classes x Objetos O objeto “carro” Classes x Objetos - Exemplos Classes em Java Exemplo: Classe Conta Como descrever Objetos? A descrição de objetos no mundo computacional consiste em mapear os objetos reais em objetos computacionais e escrever programas que dão vida a estes objetos em um sistema computacional. Métodos e Mensagens As alterações nas propriedades que definem o estado de um objeto ocorrem ao se acionar um de seus métodos. Um método é a descrição de como um objeto executa uma de suas operações. Um método é acionado através do envio de uma mensagem ao objeto. A resposta a uma mensagem é o resultado da execução do método correspondente. Métodos Conjunto de funções que representam as ações disponíveis a um objeto. Podem ser public, private ou protected public void fazAlgo() { // processamento das informações aqui } Instâncias (exemplo em Java) ... /* cria a instância F1 da classe funcionario */ funcionario F1 = new funcionario(“Joao”, “R. das Flores 325”, “M”, 1000); /* cria a instancia F2 da classe funcionario */ funcionario F2 = new funcionario(“Jose”, “R. Jasmim 333”, “M”,1000); ... F1.cadastra(); /* envia mensagem “cadastra” ao */ /* objeto F1 */ F2.cadastra(); /* idem, p/ o objeto F2 */ ... F2.altera(....); ... Programação OO Três pilares da POO Encapsulamento Herança Polimorfismo Encapsulamento Encapsulamento Encapsulamento Encapsulamento Encapsulamento Encapsulamento Encapsulamento em Java Encapsulamento em Java Encapsulamento em Java O Encapsulamento numa classe é feita pelo uso de palavras reservadas que estão associadas aos atributos e métodos da classe. Estes são designados por modificadores de visibilidade. Encapsulamento em Java Acesso público - public (Qualquer objeto que interage com a classe pode ter acesso aos elementos públicos desta). Acesso particular - private (Elementos privados serão acessados apenas pela própria classe que os define). Acesso protegido - protected (Somente classes no mesmo pacote podem acessar estes elementos). Acesso padrão - default ou package** (Somente a própria classe, suas subclasses e as classes no mesmo pacote terão acesso a estes elementos). **Não há palavra chave, aplicado na ausência de um modificador. Encapsulamento em Java Método Construtor this this é usado para fazer auto referência ao próprio contexto em que se encontra. Resumidamente, this sempre será a própria classe ou o objeto já instanciado. Esse conceito de auto referência é importante para que possamos criar métodos construtores sobrecarregados e métodos que acessam mais facilmente. Métodos Getters e Setters Set Nomeamos um método acessor com set toda vez que este método for modificar algum campo ou atributo de uma classe, ou seja, se não criarmos um método acessor set para algum atributo, isso quer dizer que este atributo não deve ser modificado. Portanto, como o valor de um atributo da classe será modificado, não é necessário que este método retorne nenhum valor, por isso, os métodos setters são void. Porém, obrigatoriamente, eles tem que receber um argumento que será o novo valor do campo. Métodos Getters e Setters Get Nomeamos um método acessor com get toda vez que este método for verificar algum campo ou atributo de uma classe. Como este método irá verificar um valor, ele sempre terá um retorno como String, int, float, etc. Mas não terá nenhum argumento. Exemplo 1 Exemplo 2 Retorna uma String representando o objeto Exemplo 2 - Continuação Exemplo 2 - Continuação @Override Quando aplicamos a anotação @Override em um método, estamos deixando explícito no código fonte que esse método é uma reescrita. Obviamente, essa anotação só pode ser aplicada em métodos reescritos. Caso contrário um erro de compilação é gerado. Herança Herança consiste a criação de uma nova classe através da inclusão de novas propriedades ou novos métodos, ou ainda, da redefinição de métodos existentes. Herança O mecanismo de herança permite a criação de uma nova classe através da: inclusão de novas propriedades ou inclusão de novos métodos ou redefinição de métodos existentes usar o código novamente (reusabilidade) A nova classe herda da classe original, as suas propriedades e os métodos que não foram alterados. Herança Herança Hierarquia de Classes Classes podem ser organizadas em hierarquias conforme a relação de herança . Mecanismo de Herança Entre uma classe e a sua superclasse, é estabelecida uma relação de especialização que é automaticamente implementada através de um mecanismo de herança. Este mecanismo automático de herança estabelece as seguintes propriedades entre uma subclasse B e a sua superclasse A: 1. B herda de A todas as variáveis e métodos de instância (os atributos da classe B, declarados como private em A , só podem ter acesso pelos métodos public de A, e não directamente) 2. B pode definir novas variáveis e novos métodos próprios. 3. B pode redefinir variáveis e métodos herdados. Classe A a herança não se aplica a variáveis e métodos de classe! Classe B Generalização / Especialização Pessoa 2 atributos 2 operações nome endereço comer dormir superclasse (mais genérica) Trabalhador anoEscolar matricular estudar categoria função trabalhar picar cartão subclasse (mais específica) 3 atributos 4 operações subclasse (mais específica) 4 atributos 4 operações especialização generalização Estudante Generalização / Especialização Podemos dizer que generalização é o agrupamento de objetos ou elementos com características comuns em um modelo ou sistemas, é uma descrição mais geral sobre o objeto referente. E a especialização é processo inverso, é a definição das particularidades de cada objeto ou elemento, são elementos mais consistentes que estendem o elemento genérico. Herança A palavra-chave extends (estende) faz com que uma subclasse herde (receba) todos os campos e métodos declarados na classe-pai (desde que ela não seja final), incluindo todas as classes-pai da classe-pai. A classe-filha pode acessar todos os atributos e métodos não privados. Ela não pode acessar (ao menos diretamente) os métodos e atributos privados (declarados com a palavra-chave private). Herança Quando estamos projetando as classes que farão parte de um sistema, é aconselhável ter em mente um conceito muito importante da programação orientada a objetos: a herança. O que um aluno, um professor e um funcionário possuem em comum? Todos eles são pessoas e, portanto, compartilham alguns dados comuns. Todos têm nome, idade, endereço, etc. E, o que diferencia um aluno de uma outra pessoa qualquer? • Um aluno possui uma matrícula; • Um funcionário possui um código, data de admissão, salário, etc; • Um professor possui um código de professor e informações relacionadas à sua formação. Herança class Animal extends Object { int peso; void mover() { /* movimentação do animal */ } } class Mamifero extends { void comer() } Animal class Ave extends Animal { void mover() {…} void voar() {…} } Sobreposição de método! Exemplo 1 Primeiro cria a classe Pessoa.java como descrito a seguir: Exemplo 1 - Continuação Logo criamos a classe Fornecedor.java como o código a seguir. Pode-se observar que o método ImprimeNome está sendo sobrescrito diferentemente da classe pai Pessoa.java. O conceito tem o nome de override. Exemplo 1 - Continuação A classe Cliente.java com o código a seguir, utilizando também o método ImprimeNome(). Exemplo 1 - Continuação E a classe Principal.java, que será a classe executora. Note que a classe Principal.java faz a chamada dos métodos e possui o método principal o main por isso estou nomeando a mesma como executora. Exemplo 2 É aqui que a herança se torna uma ferramenta de grande utilidade. Podemos criar uma classe Pessoa, que possui todos os atributos e métodos comuns a todas as pessoas e herdar estes atributos e métodos em classes mais específicas, ou seja, a herança parte do geral para o mais específico. Comece criando uma classe Pessoa (Pessoa.java) como mostrado no código a seguir: Exemplo 2 - Continuação Esta classe possui os atributos nome e idade. Estes atributos são comuns a todas as pessoas. Veja agora como podemos criar uma classe Aluno que herda estes atributos da classe Pessoa e inclui seu próprio atributo, a saber, seu número de matrícula. Eis o código: Exemplo 2 - Continuação Observe que, em Java, a palavra-chave usada para indicar herança é extends. A classe Aluno agora possui três atributos: nome, idade e matricula. Veja um aplicativo demonstrando este relacionamento: Exemplo 2 - Continuação É criada a classe IMOVEL, que possuirá um endereço e um preço. Em seguida criada uma classe chamada NOVO, que herda IMOVEL e terá um atributo chamado cor e já instanciado com a cor Verde. Por fim, criada a classe chamada IMOBILIARIA para testar o código. O usuário deverá digitar nesta classe as informações de endereço e preço e mostrar na tela as informações dos três atributos na mesma linha. Exemplo 3 Exemplo 3 - Continuação Exemplo 3 - Continuação Polimorfismo Polimorfismo, que vem do grego "muitas formas". É o termo definido em linguagens orientadas a objeto - como o Java - para a possibilidade de se usar o mesmo elemento de forma diferente. Especificamente em Java, polimorfismo se encontra no fato de podemos modificar totalmente o código de um método herdado de uma classe diferente, ou seja, sobrescrevemos o método da classe mãe. Portanto, polimorfismo está intimamente ligado a HERANÇA DE CLASSES. Polimorfismo O polimorfismo permite o uso de um objeto de uma classe derivada (classe “filha”) nas mesmas situações onde é possível o uso de um objeto da classe original (classe “mãe”). Ele tem a função de complementar a herança que permite enviar a mesma mensagem a objetos distintos, onde cada objeto responde da maneira mais apropriada para a sua classe. Polimorfismo Por exemplo, se você tem uma class Animal sabe que todo animal come, sendo que Cães por exemplo comem ração e Tigres carne. Então chama o método comer nessas 2 classes, mesmo sabendo que elas se comportam diferentemente. Polimorfismo No caso a sua chamada de método polimórfico ficaria assim: Polimorfismo Um pequeno exemplo para simplificar essa característica segue abaixo: Classe 1 possui 2 métodos: métodoA() e métodoB(). Classe 2 herda a classe 1. Classe 2 reescreve todo o métodoA() que pertence a classe 1. Levando isso a um patamar mais prático. Polimorfismo Exemplo: Sabemos que toda classe em Java herda implicitamente a classe Object. A classe Object possui alguns métodos, dentre eles o método toString(). O método toString() original, descreve qual instância de objeto está sendo utilizada. Resumidamente, ele cria um texto com o nome da classe mais um código hexadecimal que cada instância possui diferente de outra, chamado hash code (é como um RG daquela instância). Então, se tivéssemos uma classe, dentro do pacote do programa feito e usássemos o comando: System.out.println (nomeclasse.toString()). O que apareceria no console seria algo como: nomeclasse@codigohexadecimal. Então o que faremos para melhorar será usar o polimorfismo para sobrescrever o método toString(), colocando o texto da forma que desejarmos. Polimorfismo Polimorfismo Polimorfismo Sobrecarga x Sobreposição Sobreposição de Variáveis Generalização Classes Abstratas Classes abstratas (abstract classes) não diferem muito das classes que normalmente criamos, ou seja, elas também podem possuir propriedades e métodos. Porém, não é possível criar instâncias de uma classe abstrata usando o operador new. Classes Abstratas Uma classe abstrata é quase uma interface, com a exceção que ela pode conter implementações. Uma classe abstrata é usada para manter alguma programação nas classes Pai, porém não pode ser instanciada. Para ser utilizada como instância, uma classe abstrata deve ser estendida por uma classe não abstrata. Classes Abstratas Possibilita herança de código comportamento (semântica) Métodos abstratos: preservando Geralmente existe pelo menos um; São implementados nas subclasses. Não cria-se objetos: Mas podem (devem) ter construtores, para reuso. Métodos qualificados como protected para serem acessados nas subclasses. Utilização das Classes Abstratas Herdar código sem quebrar noção de subtipos, preservando o comportamento do supertipo; Generalizar código, através da abstração de detalhes não relevantes; Projetar sistemas, definindo as suas arquiteturas e servindo de base para a implementação progressiva dos mesmos. Utilização das Classes Abstratas Utilização das Classes Abstratas Exemplo 1 Exemplo 2 Exemplo 3 Utilização das Classes Abstratas Ao herdarmos nas classes Lobo e Peixe as características da classe Animal, estamos automaticamente obrigando-as a implementar o método abstrato comer(), específico para cada uma das subclasses. Em Java, é necessário adicionar a anotação @Override. Apesar de não podermos instanciar a classe abstrata, podemos declará-la como um tipo, que aceitará qualquer uma de suas implementações (como ocorre nos exemplos). Porém, nesse caso, se as subclasses tiverem métodos específicos que não pertencem ao escopo da superclasse, eles não serão reconhecidos. A Especificação super A palavra super provê acesso a partes de uma superclasse a partir de uma subclasse. Isto é muito útil quando estamos sobrepondo um método. Poderíamos reescrever o método Desligar da classe ComputadorSeguro do seguinte modo: A Especificação super class ComputadorSeguro extends Computador { private boolean executando = true; public void Desligar() { if (executando) System.out.println("Há programas rodando. Não desligue!"); else super.Desligar(); } } A Especificação super Note a chamada super.Desligar(). Esta corresponde a chamada do método Desligar declarado na superclasse Computador, o qual vai efetivamente ajustar o campo ligado para o valor false. Imaginando que o método Desligar fosse muito mais complicado, não precisaríamos recodificá-lo completamente na subclasse para acrescentar a funcionalidade que permite o desligamento apenas quando o computador estiver desocupado. Interfaces Interfaces foram concebidas para criar um modelo de implementação aumentando o baixo acoplamento entre determinadas partes de um software. Uma interface não pode possuir atributos de instância e nem métodos com implementação, mas pode possuir atributos de estáticos (de classe) e cabeçalhos de métodos que deverão ser desenvolvidos nas classes que implementarão a interface. Interfaces Muitas vezes as interfaces representam ações ou papéis para as classes. Um exemplo comum de interface é a Serializable que se encontra dentro do pacote java.io e é muito utilizada em aplicações corporativas. Quando uma classe implementa Serializable ela não precisa implementar nenhum método definido na interface, mas com esta ação o programador indica ao java que a classe pode ser serializada, transformada em um conjunto de bits para serem armazenados ou transmitidos. A serialização de uma instância armazena todos os seus dados e consegue criar um objeto semelhante na desserialização. Na verdade, uma interface nada mais é que uma classe abstrata que possui somente assinaturas de métodos. Assim, o exemplo ficaria da seguinte forma: Exemplo 1 Exemplo 1 - Explicação Se analisarmos nosso exemplo, o uso de interface na definição da classe Animal seria a alternativa mais correta. Percebam a diferença: não utilizamos a palavrachave class, e os métodos não precisam da palavra abstract, já que isso já está implícito no conceito da interface. Além disso, ao herdarmos da interface, utilizamos a palavra implements em vez de extends. Java não permite o uso de herança múltipla, ou seja, uma classe só pode estender uma outra classe. Porém, ela pode implementar diversas interfaces. Assim: Exemplo 2 Exemplo 3 Exemplo 4 Interfaces Herança Múltipla Herança múltipla, em orientação a objetos, é o conceito de herança de duas ou mais classes. Herança múltipla é a capacidade de uma classe herdar de duas ou mais classes, por exemplo a classe radio-relógio herdar da classe rádio e da classe relógio. Java por motivos de simplicidade, abandona a ideia de herança múltipla ou seja, possui apenas herança simples (uma classe possui no máximo uma classe pai), cedendo lugar ao uso de interfaces (são um conjunto de métodos e constantes (não contém atributos)).