Baixe o app para aproveitar ainda mais
Prévia do material em texto
Recife, 2010 Modelagem Orientada a Objetos Eduardo Araújo Oliveira Patrícia Azevedo Tedesco Volume 2 Universidade Federal Rural de Pernambuco Reitor: Prof. Valmar Corrêa de Andrade Vice-Reitor: Prof. Reginaldo Barros Pró-Reitor de Administração: Prof. Francisco Fernando Ramos Carvalho Pró-Reitor de Extensão: Prof. Paulo Donizeti Siepierski Pró-Reitor de Pesquisa e Pós-Graduação: Prof. Fernando José Freire Pró-Reitor de Planejamento: Prof. Rinaldo Luiz Caraciolo Ferreira Pró-Reitora de Ensino de Graduação: Profª. Maria José de Sena Coordenação Geral de Ensino a Distância: Profª Marizete Silva Santos Produção Gráfica e Editorial Capa e Editoração: Allyson Vila Nova, Rafael Lira, Italo Amorim, Gláucia Fagundes e Arlinda Torres Revisão Ortográfica: Marcelo Melo Ilustrações: Diego Almeida Coordenação de Produção: Marizete Silva Santos Sumário Apresentação ...................................................................................................4 Conhecendo o Volume 2 .................................................................................5 Capítulo 1 - Encapsulamento de Informações ..............................................7 Compreendendo melhor as interfaces .........................................................16 Capítulo 2 - Hierarquias de Classes .............................................................27 Hierarquia de Classes .................................................................................27 Capítulo 3 - Polimorfismo .............................................................................41 Sobrescrita de métodos (override) ..............................................................44 Sobrecarga de métodos (overload) .............................................................45 Polimorfismo ................................................................................................47 Considerações Finais ....................................................................................55 Conheça os Autores ......................................................................................57 Apresentação Caro(a) Cursista, Seja bem-vindo(a) ao segundo módulo do curso Modelagem Orientada a Objetos. Neste segundo módulo, vamos aprofundar os estudos que iniciamos no módulo passado, refletindo sobre as ideias de Encapsulamento de Informações (e o quanto isto pode nos ajudar a construir sistemas de software mais fáceis de manter) e as Hierarquias de Classes – e as possibilidades que a organização dos objetos em hierarquias nos trazem. Como fizemos no primeiro módulo, juntamente com a parte conceitual, vamos ver também como utilizar os conceitos aprendidos tanto na hora de modelar os nossos sistemas – e para isto vamos nos aprofundar nos estudos da linguagem UML – quanto na hora de implementar sistemas orientados a objetos. Para a implementação, vamos continuar estudando a linguagem JAVA que, como já vimos, é a linguagem Orientada a Objetos (OO) mais utilizada no mundo. O objetivo principal deste segundo módulo é aprofundar os conceitos aprendidos até agora para começar a construir hierarquias que possam depois ser estendidas e reutilizadas em sistemas futuros. Já pensou quanto trabalho isto pode nos poupar? E aí, vamos ao trabalho? Bons estudos! Eduardo Oliveira e Patricia Tedesco Conhecendo o Volume 2 Neste segundo volume, você irá encontrar o Módulo 2 da disciplina Modelagem Orientada a Objetos. Para facilitar seus estudos, veja a organização deste segundo módulo. Módulo 2 - O Modelo de objetos em detalhes Carga Horária do Módulo 2: 15 h/aula Objetivo do Módulo 2 √ Apresentar os conceitos de Encapsulamento de Informações e os tipos de Hierarquia de Classes que existem. Conteúdo Programático do Módulo 2 √ Encapsulamento e ocultamento de informações √ Hierarquia de agregação/decomposição √ Hierarquia de especialização/generalização √ Herança e Polimorfismo 6 Modelagem Orientada a Objetos Capítulo 1 O que vamos estudar neste capítulo? Neste capítulo, vamos estudar o seguinte tema: » Encapsulamento e ocultamento de informações Metas Após o estudo deste capítulo, esperamos que você consiga: » Compreender e utilizar o conceito de encapsulamento de Informações » Analisar a Importância destes conceitos para a abordagem Orientada a objetos 7 Modelagem Orientada a Objetos Capítulo 1 - Encapsulamento de Informações Vamos conversar sobre o assunto? Olá, seja bem vindo(a) ao segundo volume do curso de Modelagem Orientada a Objetos! Neste segundo volume iremos aprofundar os estudos que iniciamos no volume passado, refletindo ainda mais sobre as ideias de Encapsulamento de Informações e as Hierarquias de Classes – e as possibilidades que a organização dos objetos em hierarquias nos trazem. Neste volume teremos a oportunidade de praticar mais o conhecimento adquirido, através de exercícios práticos de programação, que resolveremos utilizando linguagem Java. Para facilitar nosso trabalho, você verá que incluímos vários exemplos práticos, que você pode usar para trabalhar na resolução dos exercícios que iremos propor. É importantíssimo para a sua formação que você seja um estudante autônomo. Para isto, o primeiro passo é buscar outras fontes de aprendizado. Leia outros livros – nós sugerimos várias opções na lista de referências! Não se limite às informações contidas neste volume. Participe do fórum de discussão, converse e discuta com seu tutor, professores e outros colegas de sala. Lembre-se que, apesar de estudar a distância, você não está sozinho...Vamos lá... Antes de passar a discutir a ideia de encapsulamento de informações, você se lembra da definição que vimos no primeiro volume? O que é encapsulamento? Encapsulamento Segundo o dicionário InFormal1: Encapsulamento Encapsular, Encapsulado, Encapsulação, Encapsulamento, Saiba Mais 1 Dicionário InFormal - http:// www.dicionarioin- formal.com. br/buscar. php?palavra= encapsulamento 8 Modelagem Orientada a Objetos » Incluído, encerrado, enclausurado... em uma cápsula. Acondicionar em cápsula... Acondicionamento em cápsula. Ato ou efeito de encapsular. » Isolamento de um corpo, substância, energia, dados... de um determinado ambiente ou entre ambientes. » Revestimento, proteção, escudo, bloqueio... de um determinado evento, isolando-o do meio circunvizinho. » Revestir, protegendo um determinado conteúdo... criando um escudo ou bloqueio destes conteúdos. » Isolamento ou intercomunicabilidade de um corpo, substância, energia, dados... entre estes elementos, destes elementos ao ambiente, ou entre ambientes. » Conter um determinado evento; isolando-o do meio circunvizinho... Encapsulamento é o processo de ocultamento das características internas, ou seja, de seus atributos e métodos (partes estrutural e comportamental, lembra?) do objeto. O encapsulamento garante que certas características não possam ser vistas ou modificadas externamente (detalhes de implementação ficam ocultos para outros objetos) [CASTRO, 2009]. Vamos ver um exemplo simples de encapsulamento? Pensemos em uma classe que representa um funcionário de uma empresa, conforme mostrado abaixo: public class Funcionario { private String depto; private double salario; private double beneficio; public void baterPonto(){ System.out.println(“Funcionario bateu o ponto”); } public void escreverRelatorioMensal(){ //colocar aqui o código do método } } Se uma outra classe de nome Diretor estendesse esta classe Funcionario, que atributos e métodos estariam encapsulados e que atributos e métodos poderiam ser acessados livremente? Como já vimos, os modificadores de acesso, neste caso, garantem que os 9 Modelagem Orientada a Objetos atributos da classe Funcionario só podem ser acessados pela própria classe. Isto acontece por conta do modificador de acesso private. Por outro lado, a classe Diretor poderia acessar tranquilamente os métodos baterPonto() e escreverRelatorioMensal(),umas vez que estes são métodos públicos (public). Para limitar o acesso aos membros do objeto (métodos e atributos), utilizamos os modificadores de acesso (que vimos no volume 1) existentes em java (public, private, protected e default). O encapsulamento garante segurança e integridade de dados, uma vez que temos controle sobre o que desejamos que seja acessado em nossas classes, a partir de outras classes. Os dois modificadores de acesso mais comumente utilizados são o public e o private (por isso daremos foco maior a eles). Normalmente, os métodos são públicos (public) e os atributos privados (private), isto ocorre pois nós desejamos que os atributos de um objeto só possam ser alterados por ele mesmo, desta forma nós inviabilizamos situações imprevistas [Java Starter]. Observe o seguinte exemplo de código: public class SuperClasse { public void exibeTexto1() { System.out.println("Texto 1"); } protected void exibeTexto2() { System.out.println("Texto 2"); } private void exibeTexto3() { System.out.println("Texto 3"); } } 10 Modelagem Orientada a Objetos public class SubClasse { public static void main(String args[]) { //chama o método da superclasse, através //do comando super.METODO_SUPERCLASSE super.mostraTexto1(); super.mostraTexto2(); //esta ultima chamada daria erro, uma vez que o //modificador de acesso é privado. Para a //subclasse, este método simplesmente //não existe. super.mostraTexto3(); } } Com este trecho de código apresentado, percebemos que, através do encapsulamento, podemos ocultar ou esconder informações que não queremos tornar pública. Isto nos garante integridade de dados e maior controle de segurança. Conforme vimos no volume 1, um carro é um bom exemplo de objeto que possui encapsulamento. Podemos dirigir um carro sem conhecer a fundo as características e detalhes sobre o funcionamento do motor. Estas complexidades estão encapsuladas para nós usuários. Quando falamos das linguagens OO, o encapsulamento protege os dados que estão dentro dos objetos, evitando assim que estes sejam alterados de maneira incorreta. Os dados, geralmente, são alterados apenas por métodos providos pelos próprios objetos. O exemplo abaixo, para pensarmos em encapsulamento em orientação a objetos, é dado por SOBRAL [2009]: Um funcionário, cujo modelo de classe é apresentado na Figura 1, possui uma identidade própria, seu nome: José da Silva. Possui também propriedades como: nome, endereço e salário. O comportamento pode ser determinado por operações como: obter nome, obter endereço, obter salário e buscar dados. As propriedades somente podem ser manipuladas através das operações definidas na interface do objeto, de modo que a forma de armazenamento das propriedades e a implementação das operações sejam desconhecidas Você Sabia? Em 1943, durante o desenvolvimento do computador Mark II, um relê dentro do computador falhou e os pesquisadores demoraram um mês para descobrir um inseto morto, uma mariposa, dentro de seus contatos. Hoje, o termo bug (inseto em inglês) é utilizado para designar pequenas falhas em softwares, que vão de pequenas perturbações até prejuízos graves. 11 Modelagem Orientada a Objetos pelas outras entidades externas (encapsulamento de informações). Uma interface modela um comportamento esperado. Perceba que os atributos são privados (somente podem ser acessados dentro da Classe Funcionario). Por este motivo, apenas os métodos públicos (que são vistos por outras classes) permitem manipulação aos atributos da classe Funcionario. Figura 1. Representação da classe Funcionario Analisando a Figura 1 percebemos que um objeto Funcionario se relaciona com outras classes de quatro maneiras: obtendo o nome do funcionário (através do método publico getNome(String)), obtendo o endereço do funcionário (através do método público getEndereço(String)), obtendo o salário do funcionário (através do método público getSalario(double) e buscando dados (através do método buscarDados(String)). Aos outros objetos, pouco importa como o objeto atualiza ou busca estes valores. Para esta camada pública é dado o nome de interface do objeto. Então, quando um objeto se relaciona com outro, ele não acessa seus recursos diretamente, mas se comunica através de sua interface. Vamos agora conhecer um pouco mais de benefícios proporcionados pelo encapsulamento de informações. Uma vez que objetos utilizam o princípio da abstração de dados, como já vimos em nosso primeiro volume, o encapsulamento de informação proporciona dois benefícios principais para o desenvolvimento de sistemas [SOBRAL, 2009]: Modularidade: o código fonte para um objeto pode ser escrito e mantido independentemente do código fonte de outros objetos (um código pode ser acessado por vários objetos, através de uma única interface). Além disso, um objeto pode ser facilmente migrado para outros sistemas. 12 Modelagem Orientada a Objetos - Por exemplo, quando a gente vai dirigir, o que importa são os pedais e o volante (e o tipo de câmbio). A motorização do carro (neste caso a implementação das funcionalidades) pouco importa. Obviamente que um motor 2.0 pode dar uma melhor resposta do que um 1.0, mas, na verdade, o que o carro faz (te levar de um canto para outro) não muda. De maneira análoga, a gente não precisa reaprender a dirigir toda vez que usa um carro a gás e um a gasolina. Neste caso, o que mudam são os métodos (a forma como o carro funciona), mas a interface é a mesma. Assim, as outras classes, por exemplo, nós, motoristas, podemos usar o carro da mesma forma. Ficou mais claro? Agora, dê uma olhada ao seu redor. Escolha dois objetos e tente definir sua interface. Você sabe quais os métodos utilizados para implementar as suas funcionalidades? Discuta as suas descobertas no fórum com seus professores e colegas. Por fim, vale lembrar que o encapsulamento permite que um objeto seja facilmente migrado para outros sistemas – em outras palavras, a gente agora pode reutilizar mais facilmente códigos que já havíamos criado. Já pensou quanta economia de trabalho? No final deste capítulo, teremos uma seção mais aprofundada e detalhada sobre as interfaces. Ocultamento de informações: um objeto tem uma interface pública que os outros objetos podem utilizar para estabelecer comunicação com ele (a troca de mensagens). O objeto mantém informações e métodos privados que podem ser alterados a qualquer hora sem afetar os outros objetos que dependem dele (isto porque os objetos acessam apenas métodos visíveis e os métodos privados são acessados apenas dentro do próprio 13 Modelagem Orientada a Objetos objeto). Ou seja, não é necessário saber como o objeto é implementado para poder utilizá-lo. Vamos aprofundar mais este conceito de ocultamento de informações. Tomando a Figura 1 como exemplo, vamos investigar o código abaixo: public class Funcionario { private String nome; private String endereco; private double salario; public String getNome() { return nome; } public String getEndereco() { return endereco; } public double getSalario() { return salario; } public void buscarDados(String nome) { //codigo aqui } } Uma classe externa que acessa os métodos públicos (interface) da classe Funcionario se preocupa apenas com as assinaturas destes métodos (getNome, getEndereco, getSalario e buscarDados). Note que a classe que chama os métodos não precisa saber como os métodos são implementados. Por exemplo, uma classe Diretor que herdasse da superclasse Funcionario poderia fazer chamadas ao método buscarDados(String) da classe pai sem saber detalhes de implementação do método. A subclasse só precisa conhecer a interface da classe, não precisa ter conhecimento sobre os códigos. Isto é ocultamento. Perceba ainda que os atributos da superclasse não são visíveis a subclasse (todossão privados). As variáveis de instância privadas podem ser manipuladas somente por métodos da classe [DEITEL, 2005]. No exemplo que vimos na Figura 1, os três atributos privados da classe Funcionario 14 Modelagem Orientada a Objetos só podem ser manipulados através dos métodos públicos. É muito comum que as classes forneçam métodos public para permitir que os clientes (isto é, outros objetos – externos – que queiram utilizar seus serviços) destas classes configurem (i.e., possam utilizar métodos set, ou seja, métodos de atribuição de valores) ou obtenham (métodos get, ou seja, métodos de obtenção de valores) variáveis de instância private. Os métodos de manipulação destas variáveis não necessariamente precisam ser chamados de set e get, contudo esta notação é adotada frequentemente. Para facilitar o entendimento, vamos discutir um exemplo prático este tipo de manipulação, que utiliza a classe Funcionario (aqui com os métodos set também), apresentada na Figura 1. public class Funcionario { private String nome; private String endereco; private double salario; public String getNome() { return nome; } public void setNome(String nome) { //this - aqui é utilizado para referen- ciar o atributo da classe //o atributo GLOBAL, ou seja, o atributo da classe está recebendo //o valor do atributo (local). this.nome = nome; } public String getEndereco() { return endereco; } public void setEndereco(String endereco) { this.endereco = endereco; } public double getSalario() { return salario; } public void setSalario(double salario) { 15 Modelagem Orientada a Objetos this.salario = salario; } } Como percebemos no código exemplo fornecido, os atributos da classe Funcionario possuem modificadores de acesso private. A única forma de manipular estes atributos é feita através dos métodos public da classe. Os atributos estão encapsulados na classe. Se os atributos fossem públicos, poderíamos modificar os valores dos atributos através de chamadas diretas a eles, a exemplo de funcionario.salario = 3500.0. Neste exemplo, funcionario seria uma instância da classe Funcionario (Funcionario funcionario = new Funcionario();). NOTA: Quando um objeto de uma subclasse é inicializado, o construtor da superclasse deve ser chamado para fazer qualquer inicialização necessária das variáveis de instância de superclasse do objeto de subclasse (new Funcionario() faz uma chamada ao construtor da classe Funcionario). Os construtores da superclasse não são herdados por subclasses. Os construtores de subclasse, entretanto, podem chamar os construtores de superclasse via a referência super [DEITEL, 2005]. Perceba que os métodos que configuram os valores de dados private devem verificar se os novos valores pretendidos são adequados (esperados); se eles não forem, os métodos set devem colocar variáveis de instância private em um estado consistente apropriado [DEITEL, 2005]. Vamos entender agora um pouco mais sobre os métodos set e get? [Java Starter]: » Métodos set ○ formato: visibilidade void(sem retorno) nome (parametro) ○ Método que atribui/modifica o valor de um atributo, é sempre composto pela palavra set[nome do atributo] e o parâmetro do mesmo tipo do atributo. Ex: setIdade(Integer idade), setSalario(Double salario). » Métodos get ○ formato: visibilidade tipoRetorno nome( ) Você Sabia? O primeiro computador a chegar no Brasil foi o UNIVAC 1105, terminado em 1951 e adquirido pelo IBGE em 1961. 16 Modelagem Orientada a Objetos ○ Método que retorna o atributo, é sempre composto pela palavra get[nome do atributo]. Ex: getIdade(), getSalario(). Compreendendo melhor as interfaces Antes de passarmos para o próximo capítulo, vamos falar um pouco mais sobre as interfaces. As interfaces fornecem um meio que permite que você lide com os objetos sabendo apenas a assinatura de seus métodos, ou seja, você não depende da (ou precisa saber sobre a) implementação dos métodos nas classes. Uma interface é como uma caixa-preta: você sabe o que deve entrar (parâmetros exigidos pelos métodos) e o que deve sair (tipo de retorno), mas não precisa se preocupar como esse processamento é realizado. Tomemos a classe Funcionário como exemplo: public class Funcionario { private String nome; private String endereco; private double salario; public String getNome() { return nome; } public String getEndereco() { return endereco; } public double getSalario() { return salario; } private void buscarDados(String nome) { //codigo aqui } } Para cada método público da classe é dado o nome de interface do objeto. Quando um objeto se relaciona com outro, ele não acessa seus recursos diretamente, mas sim sua interface. Interface é a assinatura do método (seu nome, parâmetros que recebe, tipo de retorno). 17 Modelagem Orientada a Objetos Em Java, podemos criar e definir interfaces. Java estendeu o conceito de interfaces a um nível mais flexível. Quando modelamos um sistema, podemos pensar apenas nas interfaces dos objetos (ou seja, na função de cada um deles, e no seu relacionamento com os outros), desta forma criamos uma camada extra de abstração. O uso de interfaces faz com que você pense em objetos e no relacionamento entre eles, construindo assim o sistema de uma forma consistente. Feito isso, basta começar a construção seguindo os moldes já existentes. Como no exemplo da classe Funcionário acima, temos três métodos públicos que são acessados por classes externas através das interfaces providas (getNome(), getEndereco() e getSalario()) e um método privado, acessível apenas pela própria classe. Estes métodos públicos só são acessíveis por meio de suas assinaturas. Só são reconhecidos por meio das interfaces providas. Para transformarmos a classe Funcionário em uma interface, segundo os conceitos que vimos agora, o que precisaríamos fazer? Vamos olhar no código abaixo: public interface Funcionario { public String getNome(); public String getEndereco(); public double getSalario(); } Basta utilizarmos a palavra reservada interface e disponibilizar apenas as assinaturas dos métodos (sem implementação alguma). A interface Funcionário representa um modelo de tudo aquilo que será acessível a outras classes em um objeto do tipo Funcionário. Por este motivo, todos os métodos de uma interface devem ser públicos. Qualquer classe que implemente esta interface, será também considerada do tipo Funcionário. As interfaces não podem ter atributos, contudo podem possuir constantes definidas (variáveis que utilizam os modificadores static e final conjuntamente). Exemplos de constantes que poderiam ser criadas na interface Funcionário: public static final int DIRETOR = 0; public static final int PROFESSOR = 1; Note que definimos uma interface, mas é necessário que alguma 18 Modelagem Orientada a Objetos classe implemente esta. Nós definimos métodos e demonstramos como deve ser a assinatura do método, seus parâmetros e seu tipo de retorno. A implementação da interface será de responsabilidade da classe que a implementa. Vamos visualizar um exemplo em código: public class Diretor implements Funcionario{ private String endereco; private String nome; private double salario; public String getEndereco() { return endereco; } public String getNome() { return nome; } public double getSalario() { return salario; } } A palavra reservada implements é utilizada para dizer ao compilador que a classe implementa uma interface. Quando uma classe implementa uma interface, esta deve cuidar de todos os métodos definidos na interface. Todos os métodos da interface farão parte da classe (mesmo que o desenvolvedor não decida implementar todos). Uma classe pode ainda implementar mais de uma interface, neste caso, elas são colocadas lado a lado, separadas por vírgula juntamentecom a cláusula implements. Observe o seguinte exemplo: public interface Relogio { public String getHoras(); } public interface Radio() { public void liga(); public void desliga(); public void trocaEstacao(int frequencia); } 19 Modelagem Orientada a Objetos public class RadioRelogio implements Radio, Relogio { private String horarioAtual; public String getHoras() { return horarioAtual; } public void liga() { // código aqui } public void desliga() { // código aqui } public void trocaEstacao(int frequencia) { // código aqui } } Note que todo rádio deve ligar, desligar e trocar de estação. Por este motivo uma interface Radio foi criada, para que todos os rádios sejam criados da mesma maneira. Da mesma forma, o relógio deve retornar as horas. Agora que você entendeu o que é uma interface, pensemos na seguinte pergunta: qual a diferença entre utilizar uma classe 'normal' e utilizar uma interface? A resposta é que você pode substituir a criação de objetos por objetos de outras classes que implementem as interfaces dependentes da classe e, sem muito esforço, você poderá modificar o seu sistema da maneira que desejar! Conheça Mais Aprofunde seus conhecimentos sobre encapsulamento. Consulte outras fontes de informação na internet e os livros indicados neste volume. Ao encontrar boas fontes de leitura, compartilhe este novo conhecimento com os demais colegas de sala. Compartilhe também os códigos que anda encontrando e desenvolvendo, desta forma aprenderemos de maneira mais fácil e ágil. Bons estudos! 20 Modelagem Orientada a Objetos Excelente material em PDF: http://www.t2ti.com/java_starter/modulos/Java_Basico_Modulo_04.pdf Artigo encontrado na internet: http://www.devmedia.com.br/articles/viewcomp.asp?comp=13026 Tutorial sobre Java e POO http://www.virgos.com.br/portal/JavaPOO.pdf Aula sobre encapsulamento do Prof. Rodrigo Borges: http://srv1.saojose.senai.br/prof/Prof.%20Rodrigo%20Borges/Aulas/POO/ POO_Aula9_Encapsulamento.pdf Texto introdutório do Evandro Ruiz, que esclarece um pouco sobre classes, objetos e encapsulamento: http://dfm.ffclrp.usp.br/~evandro/ibm1030/intro_classe/clas_obj.html http://www.inf.ufsc.br/poo/conceitos/index.html Mais uma introdução ao paradigma POO http://www.dca.fee.unicamp.br/cursos/POOCPP/node3.html http://www.ccuec.unicamp.br/revista/infotec/artigos/leite_rahal.html Aprenda Praticando Considere o programa abaixo e responda às seguintes questões: A classe Empregado segue os princípios do encapsulamento? Comente a respeito. Como é possível estender o código para atender os princípios do encapsulamento? Quais seriam as vantagens que isto traria? Faça as modificações necessárias no código. public class Empregado { String nome; int idade; String cpf; int depto; double salario; public Empregado() { 21 Modelagem Orientada a Objetos } public static void main(String[] args) { Empregado empregado = new Empregado(); empregado.nome = “Eduardo Oliveira”; empregado.idade = 27; empregado.cpf = “012345678-99”; empregado.depto = 1; empregado.salario = 510.00; System.out.println(“Empregado “+empregado .nome+” tem “+empregado.idade+” anos e ganha um salário de “+empregado.salario+” reais”); } } Antes de olhar a solução, observe o código. Pense sobre tudo o que acabamos de ver neste capítulo. O código está de acordo com o que vimos? Podemos/devemos fazer alguma modificação no código para torná-lo melhor? Solução: Conforme já vimos no volume 1, quando os atributos da classe não tem modificador de acesso definido explicitamente, ele é considerado default ou friendly. E o que isto significa? Significa que este atributo é como o modificador public, mas somente dentro do package (dentro do mesmo pacote). Todas as classes de um mesmo package (e apenas estas) podem acessar um membro “default”. É importante ter cuidado com a visibilidade default para atributos da classe. A depender do tamanho dos pacotes, muitos dados podem ficar expostos. Identificado que os atributos se encontram desta forma na classe Empregado, o que podemos perceber? Os atributos não estão em conformidade com o encapsulamento de informações. Da forma como se encontram, os atributos não são acessados apenas pela classe. Os atributos podem ser acessados por classes que se encontram no mesmo pacote desta. Vamos reescrever este código para atender os princípios do encapsulamento? Isto irá garantir uma maior segurança e integridade dos dados. Para resolver o problema, o que devemos fazer? » Adicionar os modificadores de acesso private aos atributos da classe 22 Modelagem Orientada a Objetos » Criar métodos de manipulação set e get Vamos ver novamente o código após as sugestões de mudança: public class Empregado { private String nome; private int idade; private String cpf; private int depto; private double salario; public Empregado() { } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } public int getIdade() { return idade; } public void setIdade(int idade) { this.idade = idade; } public String getCpf() { return cpf; } public void setCpf(String cpf) { this.cpf = cpf; } public int getDepto() { return depto; } public void setDepto(int depto) { this.depto = depto; } 23 Modelagem Orientada a Objetos public double getSalario() { return salario; } public void setSalario(double salario) { this.salario = salario; } public static void main(String[] args) { Empregado empregado = new Empregado(); empregado.setNome(“Eduardo Oliveira”); empregado.setIdade(27); empregado.setCpf(“012345678-99”); empregado.setDepto(1); empregado.setSalario(510.00); System.out.println(“Empregado “+empregado .getNome()+” tem “+empregado.getIdade()+” anos e ganha um salário de “+empregado.getSalario()+” reais”); } } Agora, seguramente, apenas quem tem acesso direto aos atributos da classe Empregado é a própria classe Empregado. As demais classes que estenderem esta ou estiverem no mesmo pacote, terão que acessar os métodos set e get para manipularem os atributos. Atividades e Orientações de estudo Exercícios: Quais são as restrições impostas pelos modificadores de acesso public, protected e private em Java? O modificador de acesso implícito impõe as mesmas restrições do modificador protected? Justifique a sua resposta. O metodo main de uma classe deve, obrigatoriamente, usar o modificador public? Justifique a sua resposta. Crie uma classe em Java que represente Pessoas e que: a) contenha os atributos nome, idade e altura; b) encapsule os atributos; c) crie os métodos set e get para manipular os atributos; d) crie um 24 Modelagem Orientada a Objetos método main que instancie 3 pessoas e adicione para cada um dos objetos criados um nome, uma idade e uma altura; d) ainda no método main, exiba os valores que estão nos atributos dos objetos criados. Crie uma classe em Java que represente MediaDeNotas e que: a) contenha os atributos nota1 e nota2; b) encapsule os atributos; c) crie os métodos set e get para manipular os atributos; d)crie um método para calcular a média de dois valores (definidos diretamente a partir do main()); e) crie um método que imprima os alunos (10) que foram aprovados por média e aqueles que precisam ir para a final; f) crie um método main que exiba as notas e as médias dos alunos aprovados e dos alunos na final. Discuta suas soluções com seu tutor, professores e colegas de sala. Compartilhe sua solução no fórum de discussões! Vamos fazer de nosso fórum de discussão a nossa comunidade de POO e Java. Atividades Vamos trocar ideias no fórum de discussão. Converse com seus colegas, discuta sobre o assunto, leia mais sobre o temaabordado neste capítulo. É preciso que você acesse o ambiente. Você pode aprofundar seu aprendizado ainda mais consultando os livros indicados nas referências bibliográficas deste volume, e acessando os links sugeridos na seção Conheça Mais. É importante que você não se prenda a apenas esta fonte de aprendizado. Discuta o assunto com seus colegas, seu tutor e professores. Exercite! Utilize o Eclipse para simular todos os programas demonstrados aqui como exemplos. Atividade de Avaliação Que tal a gente colocar em prática o que aprendeu? Nesta semana, vamos criar uma aplicação de controle acadêmico. Nela, utilize os conceitos que vimos no capítulo para, dada uma lista de alunos, atribuirmos suas notas, calcular médias, e imprimir a situação de cada um. Implemente sua solução no Eclipse, e poste os resultados encontrados. Você deve criar um novo projeto Java no Eclipse, uma nova classe e, seus atributos e métodos. Não esqueça de pensar no encapsulamento dos dados. Para este exercício, considere os seguintes dados como entrada (receba o nome e as notas como entrada e forneça o nome do aluno, 25 Modelagem Orientada a Objetos sua média e situação como saída): Nome Nota 1 Nota 2 Eduardo 2.7 5.5 Patricia 9.0 10.0 Rafael 4.0 8.1 Isabella 8.5 9.2 Suellen 4.0 10.0 Ana 8.9 6.0 Carlos 2.5 10.0 Claudio 6.3 8.9 Emiria 5.0 7.5 Zezano 7.5 9.0 Para este exercício, pense ainda em utilizar uma estrutura de repetição contada em Java, para receber os 10 nomes e notas. Vamos Revisar? Resumo Você estudou, neste capítulo, o encapsulamento e ocultamento de informações. Compreendemos, através de diversos exemplos, a importância dos modificadores de acesso e, dos métodos set e get como manipuladores de dados. Vimos que provendo apenas as informações que desejamos em cada classe que desenvolvemos, garantimos maior segurança e integridade dos dados. Aprendemos ainda a importância das interfaces para a modularização e reuso de códigos na POO. 26 Modelagem Orientada a Objetos Capítulo 2 O que vamos estudar neste capítulo? Neste capítulo, vamos estudar o seguinte tema: » Hierarquias de Classes Metas Após o estudo deste capítulo, esperamos que você consiga: » Compreender e utilizar o conceito de hierarquia de classes » Aprender a reusar código comum entre classes através do mecanismo de herança » Representar herança com a linguagem gráfica UML » Refletir sobre e analisar a Importância destes conceitos para a abordagem Orientada a objetos 27 Modelagem Orientada a Objetos Capítulo 2 - Hierarquias de Classes Vamos conversar sobre o assunto? Olá, seja bem vindo(a) ao segundo capítulo do segundo volume do curso de Modelagem Orientada a Objetos! Até aqui, nos nossos estudos sobre o paradigma Orientado a Objetos, já vimos o que é uma Classe, aprendemos também que um objeto nada mais é do que a instanciação de uma classe e que um dos pilares da Orientação a Objetos é o encapsulamento. Estudamos ainda um pouco sobre a linguagem Java e a linguagem UML. Neste capítulo nós iremos continuar nossos estudos sobre a programação Orientada a Objetos. O próximo tópico a estudarmos é hierarquia de classes ou herança. É importantíssimo que você busque outras fontes de aprendizado. Leia outros livros! Não se acomode às informações contidas neste volume. Participe do fórum de discussão, converse e discuta com seu tutor, professores e outros colegas de sala. Vamos lá... Hierarquia de Classes Na POO podemos definir um conjunto de classes em uma estrutura hierárquica onde cada uma das classes “herda” características das suas superiores nesta estrutura [Java Starter]. Como já vimos no volume 01, um cachorro ou um humano herdam características de uma superclasse (classe pai) Mamiferos (que possui raça como atributo e os métodos mamar() e comer(), que são comuns a todos os mamíferos). Este exemplo é novamente ilustrado na Figura 2. 28 Modelagem Orientada a Objetos Figura 2. Exemplo de herança entre classes Se tomarmos nós como exemplos, herdamos características de nossos pais. Por sua vez, nossos pais herdaram características de nossos avós e assim por diante. Quando utilizamos herança no nosso código, estamos tentando implementar esta propriedade da natureza. Como forma de aprendermos sobre herança de maneira mais clara, vamos analisar, passo a passo um exemplo prático. Pensemos em um sistema para controle de funcionários de uma instituição de ensino. Esta instituição tem os seguintes tipos de funcionários: Diretor, Professor e Secretária. Para este problema, poderíamos criar uma classe distinta para representar cada um dos tipos de funcionários, conforme ilustrado no trecho de código a seguir: Classe Diretor public class Diretor { private String depto; private double salario; public String getDepto() { return depto; } public void setDepto(String depto) { this.depto = depto; } public double getSalario() { 29 Modelagem Orientada a Objetos return salario; } public void setSalario(double salario) { this.salario = salario; } public void baterPonto(){ //colocar aqui o código do método } public void escreverRelatorioMensal(){ //colocar aqui o código do método } public void demitirFuncionario(){ //colocar aqui o código do método } public void contratarFuncionario(){ //colocar aqui o código do método } } Classe Professor: public class Professor { private String depto; private double salario; public String getDepto() { return depto; } public void setDepto(String depto) { this.depto = depto; } public double getSalario() { return salario; } public void setSalario(double salario) { this.salario = salario; } 30 Modelagem Orientada a Objetos public void baterPonto(){ //colocar aqui o código do método } public void escreverRelatorioMensal(){ //colocar aqui o código do método } public void ministrarAulas(){ //colocar aqui o código do método } } Classe Secretaria public class Secretaria { private String depto; private double salario; public String getDepto() { return depto; } public void setDepto(String depto) { this.depto = depto; } public double getSalario() { return salario; } public void setSalario(double salario) { this.salario = salario; } public void baterPonto(){ //colocar aqui o código do método } public void escreverRelatorioMensal(){ //colocar aqui o código do método } 31 Modelagem Orientada a Objetos public void agendarCompromissos(){ //colocar aqui o código do método } } Como podemos perceber, exceto pelos trechos de código que estão destacados pelo retângulo, todos os demais atributos e métodos das classes são iguais. Os retângulos destacam os comportamentos que são particulares a cada tipo de profissional (por exemplo, é uma atribuição exclusiva da secretária agendar compromissos). Se pensarmos que futuramente poderemos ter novos funcionários que também terão depto e salário, e que também irão bater ponto e escrever relatórios mensais, teríamos que criar tantas classes quantos funcionários surgissem. Além disso, teríamos que reescrever o mesmo código para todas as novas classes (o que também aumentaria a possibilidade de erros, não é mesmo?). E se precisássemos adicionar um novo atributo aos funcionários como, por exemplo, o CPF destes? Teríamos que alterar todas as classes. Percebem que a manutenção do código fica complexa? Uma maneira de solucionar este problema e tornar o código mais simples é através do uso de hierarquias de classes. No nosso caso, podemos criar um objeto de nome Funcionario e manter neste todos os atributos e métodos que são comuns a todos os funcionários. Esta nova classe seria a classe pai (superclasse) das demais classes que acabamos de desenvolver. As classes Diretor, Professor e Secretaria herdariam então da classe Funcionário.Para a gente ter uma ideia melhor de como ficaria organizada a hierarquia de classes, que tal utilizarmos a linguagem UML? A Figura 3 mostra o resultado. 32 Modelagem Orientada a Objetos Figura 3. Representação em UML de herança, na nossa aplicação do controle de funcionários Viu como fica mais simples? A gente agora não precisa mais ficar repetindo código. É só colocar o que é comum na superclasse (também conhecida como classe pai), que as classes filhas já compartilham estas características (atributos e métodos). Vamos olhar agora como ficaria o código das classes da figura 3? A classe Funcionário ficaria então da seguinte maneira: public class Funcionario { private String depto; private double salario; public String getDepto() { return depto; } public void setDepto(String depto) { this.depto = depto; } public double getSalario() { return salario; } public void setSalario(double salario) { this.salario = salario; } 33 Modelagem Orientada a Objetos public void baterPonto(){ //colocar aqui o código do método } public void escreverRelatorioMensal(){ //colocar aqui o código do método } } Perceba que esta classe possui apenas os atributos e métodos comuns a todas as classes filhas (subclasses – Diretor, Professor, Secretaria). Como criamos a classe Funcionário, os métodos e atributos que antes eram replicados em todas as classes filhas não serão mais necessários. Desta forma, faremos com que as subclasses estendam (palavra reservada extends) a superclasse. Vamos ver agora como ficariam as subclasses? Classe Diretor public class Diretor extends Funcionario { public void demitirFuncionario(){ //colocar aqui o código do método } public void contratarFuncionario(){ //colocar aqui o código do método } } Classe Professor public class Professor extends Funcionario { public void ministrarAulas(){ //colocar aqui o código do método } } Classe Secretaria public class Secretaria extends Funcionario { public void agendarCompromissos(){ //colocar aqui o código do método } 34 Modelagem Orientada a Objetos } Se a classe Professor quiser acessar o método baterPonto() da classe Funcionario (superclasse), o que podemos fazer? Basta criarmos uma instância da classe Professor e chamar o método. Não é simples? Professor prof = new Professor(); prof.baterPonto(); Apesar da classe Professor não possuir o método baterPonto(), esta classe herda da classe Funcionario, que possui o método. Se adicionarmos um novo método na classe Funcionario, todas as classes que herdam dela também terão acesso a este novo método. Até o momento, vimos as relações “é um” de hierarquia de classes. Os objetos de subclasse podem ser tratados como objetos de superclasse. Isto faz sentido porque a subclasse tem membros correspondentes a cada um dos membros da superclasse. A atribuição na outra direção não é possível, uma vez que atribuir um objeto de superclasse a uma referência de subclasse deixaria os membros adicionais da subclasse indefinidos. Uma referência a um objeto de subclasse pode ser convertida implicitamente em uma referência a um objeto de superclasse porque um objeto de subclasse é um objeto de superclasse por herança [DEITEL, 2005]. Em relação a superclasses e subclasses, existem quatro maneiras de misturar e corresponder as referências [DEITEL, 2005]: 1. Referenciar um objeto de superclasse com uma referência de superclasse. a. Dentro da superclasse podemos acessar os objetos da superclasse 2. Referenciar um objeto de subclasse com uma referência de subclasse. a. Dentro da subclasse podemos acessar os objetos da subclasse. 3. Referenciar um objeto de subclasse com uma referência de superclasse é seguro porque o objeto de subclasse também é um objeto de sua superclasse. a. Dentro da subclasse podemos acessar um objeto da 35 Modelagem Orientada a Objetos superclasse, uma vez que ao estendermos a superclasse, tudo que é da superclasse passa a ser visivel dentro da subclasse. 4. Referenciar um objeto de superclasse com uma referência de subclasse é um erro de sintaxe. a. A subclasse, ao herdar a superclasse, tem acesso aos métodos e atributos da superclasse, contudo, o inverso não é verdade. Uma superclasse sequer conhece as classes que herdam de si. Ainda pensando em relacionamentos entre classes, uma classe pode ter objetos de outras classes como membros. Este é o relacionamento tem um. Estes relacionamentos do tipo tem um, criam novas classes por composição. Neste capítulo vimos o exemplo da classe Funcionario, que poderia ter, dentro de si, objetos de classes NumeroTelefone, Endereco, DataNascimento, por exemplo. Note que Funcionario não é um NumeroTelefone. É apropriado dizermos que Funcionário tem um número de telefone. NOTA: Em Java qualquer classe que não herde explicitamente de outra classe, automaticamente será subclasse direta da classe java. lang.Object, que é a superclasse de mais alto nível da linguagem. Pensemos agora um pouco em herança múltipla. A herança múltipla possibilita o compartilhamento de atributos e operações de duas ou mais classes em uma subclasse. Esta característica não é suportada pela linguagem Java. Java possui apenas herança simples (uma classe possui no máximo uma classe pai ou superclasse), mas permite que uma classe implemente várias interfaces. Quando estamos programando em Java, frequentemente sentimos a necessidade de trabalhar com várias classes. Muitas vezes, classes diferentes têm necessidades comuns; a herança nos permite que utilizemos classes já existentes, no lugar de criarmos uma nova classe com todas essas características. A herança contribui bastante para a reutilização de código. Este é um recurso importante e bastante utilizado na OO. 36 Modelagem Orientada a Objetos Conheça Mais Aprofunde seus conhecimentos sobre hierarquia de classes. Consulte outras fontes de informação na internet e os livros indicados neste volume. Ao encontrar boas fontes de leitura, compartilhe este novo conhecimento com os demais colegas de sala. Compartilhe também os códigos que anda encontrando e desenvolvendo, desta forma aprenderemos de maneira mais fácil e ágil. Bons estudos! Artigo encontrado na Wikipedia: http://pt.wikipedia.org/wiki/Heran%C3%A7a_%28programa%C3%A7%C3% A3o%29 Introdução interessante a POO http://pt.kioskea.net/contents/poo/poointro.php3 http://dfm.ffclrp.usp.br/~evandro/ibm1030/constru/heranca.html Conheça mais! Aproveite este momento! Aprenda Praticando Dada a tabela abaixo, utilize seus conhecimentos para organizar as classes hierarquicamente, de acordo com os métodos e atributos fornecidos. Você deve ainda pensar na criação de uma nova classe, que seria a superclasse das classes fornecidas na tabela. Bicicleta Moto Possui marca Possui marca Possui fabricante Possui fabricante Pode acelerar Pode acelerar Pode buzinar Pode buzinar Pode frear Pode frear Não precisa abastecer Pode abastecer Solução: Como podemos notar, ambos os objetos tem atributos e métodos e 37 Modelagem Orientada a Objetos comuns. Para evitar a replicação de informações, podemos criar uma nova classe pai com estas informações. Se criarmos uma nova classe de nome MeiosTransporte, podemos criar uma classe como: public class MeiosTransporte { private String marca; private String fabricante; public String getMarca() { return marca; } public void setMarca(String marca) { this.marca = marca; } public String getFabricante() { return fabricante; } public void setFabricante(String fabricante) { this.fabricante = fabricante; } public void acelerar(){ //codigo aqui } public void buzinar(){ //codigo aqui } public void frear(){ //codigo aqui } } Agora, podemos criar as classes da tabela de maneira a herdarem da classe MeiosTransporte, concorda? Perceba ainda que não criamoso método abastecer() na classe pai porque bicicleta não utiliza este método. Neste caso, a solução fica mais elegante se criarmos este método no próprio objeto que irá representar a Moto. Teríamos algo como: 38 Modelagem Orientada a Objetos public class Bicicleta extends MeiosTransporte{ //não precisaríamos criar os métodos e atributos da tabela, visto que todos ja se encontram na superclasse. } public class Moto extends MeiosTransporte{ public void abastecer(){ //codigo aqui } } Viu como é simples? Caso tenha ficado com alguma dúvida, participe em nosso fórum e nos chats. Consulte o seu tutor, professores e colegas. Atividades e Orientações de estudo Exercícios: Dada a tabela abaixo, utilize seus conhecimentos para organizar as classes hierarquicamente, de acordo com os métodos e atributos fornecidos. Você deve ainda pensar na criação de uma nova classe, que seria a superclasse das classes fornecidas na tabela. Após a solução ser codificada em Java, represente esta em UML, através do diagrama de classe. Cachorro Morcego Golfinho Possui patas Possui asas Possui nadadeiras Possui dentes Possui dentes Possui dentes Pode mamar Pode mamar Pode mamar Pode correr Pode voar Pode nadar Discuta suas soluções com seu tutor, professores e colegas de sala. Compartilhe sua solução no fórum de discussões! Vamos fazer de nosso fórum de discussão a nossa comunidade de POO e Java. 39 Modelagem Orientada a Objetos Atividades de Pesquisa Você pode aprofundar seu aprendizado ainda mais consultando os livros indicados nas referências bibliográficas deste volume, e acessando os links sugeridos na seção Conheça Mais. É importante que você não se prenda a apenas esta fonte de aprendizado. Discuta o assunto com seus colegas, seu tutor e professores. Exercite! Utilize o Eclipse para simular todos os programas demonstrados aqui como exemplos. Vamos Revisar? Resumo Você estudou, neste capítulo, a hierarquia de classes. Vimos o conceito de herança, sua importância e diversos exemplos em códigos Java. Vimos ainda representações UML de relacionamentos de herança entre classes. 40 Modelagem Orientada a Objetos Capítulo 3 O que vamos estudar neste capítulo? Neste capítulo, vamos estudar o seguinte tema: » Polimorfismo Metas Após o estudo deste capítulo, esperamos que você consiga: » Compreender e utilizar o conceito de sobrescrita de métodos (override) » Compreender e utilizar o conceito de sobrecarga de métodos (overload) » Analisar a Importância destes conceitos para a abordagem Orientada a objetos 41 Modelagem Orientada a Objetos Capítulo 3 - Polimorfismo Vamos conversar sobre o assunto? Olá, seja bem vindo(a) ao terceiro capítulo do segundo volume do curso de Modelagem Orientada a Objetos! Já vimos bastante sobre encapsulamento de informações e sobre hierarquia de classes. Que tal aprofundarmos agora nosso conhecimento sobre herança? Vamos estudar agora polimorfismo e entender como lidar melhor com os métodos e atributos das classes. Como forma de facilitar nosso entendimento sobre o assunto, vamos continuar com o mesmo exemplo do capítulo 2. Lembram da hierarquia que criamos para representar Professor, Diretor e Secretaria como Funcionários? Esta hierarquia foi apresentada na Figura 3, conforme abaixo: Figura 4. Representação em UML de herança, na nossa aplicação do controle de funcionários Vamos recordar um pouco mais sobre o problema. Apesar da classe Professor não possuir o método baterPonto(), esta classe herda da classe Funcionario, que possui o método. O compilador sabe que existe a herança. Se adicionarmos um novo método na classe Funcionario, todas as classes que herdam dela 42 Modelagem Orientada a Objetos também terão acesso a este novo método. Que tal ilustrarmos este exemplo na prática? Vamos lá... Vamos admitir que todos os funcionários passarão a ter acesso a um benefício em tíquete alimentação. Este benefício é um bônus, além do salário que já ganham. Assim como o salário, ele pode variar de funcionário para funcionário. Como este é um benefício comum a todos, podemos tranquilamente adicioná-lo à classe Funcionário. Nossa classe Funcionário ganharia um atributo a mais, de nome benefício. A classe ficaria da seguinte maneira: public class Funcionario { private String depto; private double salario; private double beneficio; public double getBeneficio() { return beneficio; } public void setBeneficio(double beneficio) { this.beneficio = beneficio; } public String getDepto() { return depto; } public void setDepto(String depto) { this.depto = depto; } public double getSalario() { return salario; } public void setSalario(double salario) { this.salario = salario; } public void baterPonto(){ //colocar aqui o código do método } public void escreverRelatorioMensal(){ 43 Modelagem Orientada a Objetos //colocar aqui o código do método } } A hierarquia de classes garante que as mudanças na classe pai (superclasse), sejam acessadas e estejam disponíveis em todas as classes filhas (subclasses). Agora que sabemos disto, reflita um pouco sobre a pergunta a seguir: Se implementarmos um método na classe pai, por exemplo, o método baterPonto(), de uma maneira, todas as subclasses obrigatoriamente terão que seguir este mesmo comportamento? public void baterPonto(){ System.out.println(“Funcionario bateu o ponto”); } Desta forma, qualquer subclasse que herda da superclasse Funcionario, ao chamar o método baterPonto() terá a mesma mensagem: Funcionario bateu o ponto. Por exemplo, vamos simular uma chamada a superclasse feita a partir do main. public static void main(String[] args) { Diretor diretor = new Diretor(); diretor.baterPonto(); } Se compilarmos e executarmos este código, teremos a seguinte mensagem como saída: Funcionario bateu o ponto. Apesar de termos uma instância da classe Diretor, Diretor herda de Funcionario. Por este motivo, a saída do aplicativo será a mensagem contida na superclasse. E se quiséssemos imprimir a mensagem: Diretor bateu o ponto? Será que conseguiríamos? Desta forma poderíamos personalizar nossas mensagens para cada uma das classes filhas, concorda? A boa notícia é que SIM, isto é possível! Vamos aprofundar um pouco mais nossos conhecimentos? Para que consigamos personalizar nossas mensagens, utilizamos dois conceitos da orientação a objetos: A sobrescrita de métodos (override) e a sobrecarga de métodos (overload). 44 Modelagem Orientada a Objetos Sobrescrita de métodos (override) O que estamos tentando resolver em nosso código atual? Estamos tentando modificar um comportamento de um método que herdamos da classe pai (superclasse) dentro de nossas classes filhas (subclasses). Se quiséssemos, ainda pensando no exemplo anterior, através da instância da classe Diretor, imprimir a mensagem: Diretor bateu o ponto, o que precisaríamos fazer? Teríamos que sobrescrever o método da classe pai DENTRO da classe filha. Ou seja, o método baterPonto() existente na superclasse teria que ser modificado dentro da subclasse. Isto faria com que apenas a subclasse que sobrescreveu o método tivesse o novo comportamento. Se modificarmos o comportamento da classe baterPonto() dentro de Diretor, teremos uma nova mensagem APENAS nesta classe. Note que todas as outras subclasses (Professor e Secretaria) continuariam a ter a mensagem: Funcionario bateu o ponto, visto que elas continuam herdando da classe Funcionario e não sobrescreveram seus métodos. Vamos ver isto na prática: Nossa classe Diretor foi modificada (as demais classes continuam da mesma maneira) e se apresenta agora da seguinte maneira: public class Diretor extends Funcionario { public void demitirFuncionario(){ //colocar aqui o código do método } public void contratarFuncionario(){ //colocar aqui o código do método } public voidbaterPonto(){ System.out.println(“Diretor bateu o ponto”); } } No método main, ao criarmos duas instâncias de classe distintas, uma para a classe Diretor e outra para a Classe Professor, e realizarmos chamadas ao método baterPonto(), que resultado 45 Modelagem Orientada a Objetos teremos como saída? public static void main(String[] args) { Diretor diretor = new Diretor(); diretor.baterPonto(); Professor professor = new Professor(); professor.baterPonto(); } Teríamos a seguinte saída: Diretor bateu o ponto Funcionario bateu o ponto A mensagem seria exibida nesta ordem, obrigatoriamente, dada a ordem com que os métodos são chamados. Primeiro o método baterPonto() é chamado a partir da instância da classe Diretor (por isso a mensagem personalizada, pois o método foi sobrescrito), seguido pela instância da classe Professor. Não é simples? Para sobrescrever um método de uma superclasse, precisamos apenas criar este mesmo método, com o mesmo nome, mesmos parâmetros e mesmo tipo de retorno, dentro da subclasse. Quando um método tem o mesmo nome, mesmos parâmetros e tipo de retorno, dizemos que o método possui a mesma assinatura. Vamos agora entender o que é sobrecarga de métodos (overload). Sobrecarga de métodos (overload) Já entendemos o que é sobrescrita, mas o que vem a ser sobrecarga? Sobrescrita, como vimos, obrigatoriamente o método sobrescrito na subclasse deve ter a mesma assinatura do método da superclasse. No caso da sobrecarga, o método na subclasse possui o mesmo nome de um método da superclasse, mas este pode modificar os parâmetros recebidos (assinatura do método). Tomemos novamente a nossa classe Diretor como exemplo: public class Diretor extends Funcionario { public void demitirFuncionario(){ //colocar aqui o código do método } public void contratarFuncionario(){ 46 Modelagem Orientada a Objetos //colocar aqui o código do método } public void baterPonto(){ System.out.println(“Diretor bateu o ponto”); } public void baterPonto(String msg){ System.out.println(msg); } } Perceba que, neste caso, temos um exemplo de sobrescrita e um exemplo de sobrecarga do método baterPonto(). No primeiro caso, o método possui a mesma assinatura do método da superclasse (Funcionario). No segundo caso, o método modifica a assinatura do método da superclasse, adicionando um parâmetro do tipo String à assinatura do método. O que aconteceria se no método main realizássemos as seguintes chamadas: public static void main(String[] args) { Diretor diretor = new Diretor(); diretor.baterPonto(); diretor.baterPonto(“Eduardo bateu o ponto”); Professor professor = new Professor(); professor.baterPonto(); } Você consegue identificar as saídas que teríamos? Pense um pouco, não é difícil perceber. Vamos pensar neste exemplo, passo a passo. Primeiro criamos uma instância de nome diretor da classe Diretor. Feito isso, realizamos uma chamada ao método baterPonto() desta classe (Diretor). E porque esta chamada não é ao baterPonto() da classe Funcionario (já que Diretor herda de Funcionario)? Justamente porque este método existe na própria subclasse, ele foi sobrescrito. Caso o método não existisse na subclasse, o compilador automaticamente acessaria o método da superclasse. Neste caso, o método baterPonto() da classe Diretor exibiria a seguinte mensagem Diretor bateu o ponto. Em seguida, ainda com a instância da classe Diretor realizamos uma chamada ao método sobrecarregado baterPonto(String). O método está sobrecarregado porque possui 47 Modelagem Orientada a Objetos assinatura diferente do método da superclasse. Neste caso, a mensagem a ser exibida seria a mensagem contida dentro do método baterPonto(String) contido na classe Diretor. A saída seria a mensagem Eduardo bateu o ponto. Por fim, criamos uma instância da classe Professor e realizamos uma chamada ao método baterPonto(). Como sabemos, a classe Professor não possui método baterPonto(), por este motivo, o compilador automaticamente chama o método baterPonto() da superclasse. Neste caso, a mensagem exibida como saída será: Funcionario bateu o ponto. Você pode escrever este código no Eclipse e simular este exercício. Quanto mais você praticar, maior será o seu aprendizado. O override e o overload são interessantes porque permitem ao desenvolvedor uma especialização dos métodos, isto feito somente quando desejarem. A possibilidade de redefinir um método em classes que são herdeiras de uma classe básica chama-se de especialização. Imagine um jogo de xadrez que contém os objetos rei, rainha, torre e peão, herdando cada um da superclasse Peça. O método movimentarPeca() (contido na superclasse e nas subclasses) poderá, graças a sobrescrita deste método (nas subclasses), realizar o movimento apropriado para cada um dos objetos (rei, rainha, torre e peão). Polimorfismo Polimorfismo significa "várias formas", que significa um único nome representando um código diferente. Um nome, vários comportamentos. Numa linguagem de programação, isto significa que pode haver várias formas de fazer uma mesma atividade (isto logo ficará claro para você). Quando falamos em polimorfismo estamos falando de chamadas de métodos. Em Java, o polimorfismo se manifesta apenas em chamadas de métodos (por isso vimos anteriormente a sobrescrita e a sobrecarga de métodos, para facilitar este entendimento). Pensemos mais sobre a definição de polimorfismo: Polimorfismo significa que uma chamada de método pode ser executada de várias formas (ou polimorficamente). Quem decide "a forma" é o objeto que recebe a chamada. Essa última frase é muito importante, pois ela encerra a essência do polimorfismo. Leia a frase novamente. Ela significa o seguinte: Se um objeto "homem" chama um método 48 Modelagem Orientada a Objetos emitirSom() de um objeto "mamifero", então o objeto "mamifero" decide a forma de implementação do método. Mais especificamente ainda, é o tipo do objeto "mamifero" que importa. Para concretizar melhor, o objeto homem ao chamar o método emitirSom() da classe mamífero vai ter como saída um grito humano; caso o mesmo método fosse chamado por um objeto “cavalo”, este teria como saída um relinchado. O que importa portanto, é o tipo do objeto receptor. Polimorfismo é quando "o mesmo método" responde de diferentes maneiras. Quando fazemos sobrecarga criamos um novo método (pois modificamos sua assinatura original). Mas uma sobrescrita é polimorfismo. Alguns autores divergem desta teoria, assumindo que a sobrecarga de métodos é também um polimorfismo, conhecido como polimorfismo Ad-Hoc. Vamos ver como o polimorfismo funciona através de um exemplo: Vamos criar uma classe que represente animais, e que possua apenas um método, som(): public class Animal { public void som(){ } } Agora, vamos criar duas classes: uma representando um cachorro e outra representando um gato: public class Cachorro extends Animal{ public void som(){ System.out.println(“au-au”); } } public class Gato extends Animal{ public void som(){ System.out.println(“miau”); } } Por último, vamos executar estas chamadas através do método main: public static void main(String[] args) { 49 Modelagem Orientada a Objetos Animal animal = new Animal(); Cachorro cachorro = new Cachorro(); Gato gato = new Gato(); animal = cachorro; animal.som(); animal = gato; animal.som(); } Teremos as seguintes saída: au-au miau Perceba que, enquanto a herança se refere às classes (e à sua hierarquia), o polimorfismo diz respeito aos métodos dos objetos. Você pode explorar o polimorfismo para adicionar uma nova funcionalidade em seu sistema, a qualquer momento. Você pode adicionar novas classes, que tenham funcionalidades ainda não imaginadas quando o programa foi escrito pela primeira vez – isso sem ter que mudar o código já existente. Por issoque não acessamos o código da classe Animal, no exemplo acima, diretamente. Note também que em OO o conceito de polimorfismo está diretamente ligado aos conceitos de encapsulamento e herança, onde um conceito completa o outro. Conheça Mais Aprofunde seus conhecimentos sobre Polimorfismo. Consulte outras fontes de informação na internet e os livros indicados neste volume. Ao encontrar boas fontes de leitura, compartilhe este novo conhecimento com os demais colegas de sala. Compartilhe também os códigos que anda encontrando e desenvolvendo, desta forma aprenderemos de maneira mais fácil e ágil. Bons estudos! Exercício resolvido de Polimorfismo: http://ltodi.est.ips.pt/atai/index_files/Ex%20da%20Oficina.pdf O que é polimorfismo: http://www.dsc.ufcg.edu.br/~jacques/cursos/p2/html/oo/o_que_e_ polimorfismo.htm Herança: 50 Modelagem Orientada a Objetos http://www.tiexpert.net/programacao/java/heranca.php Aproveite este momento! Aprenda Praticando Monte uma classe Animal, com os métodos: comer, andar, voar, nadar e emitir som. Após a criação desta classe, crie três subclasses de nome Cachorro, Pinguim e Tubarão que herdam de Animal. Sobrescreva os métodos necessários para cada uma destas subclasses. Ao final, crie uma classe Teste com um método main para testar os métodos sobrescritos. Solução: public class Animal { public void comer(){ System.out.println("Animal comendo"); } public void andar(){ System.out.println("Animal andando"); } public void voar(){ System.out.println("Animal voando"); } public void nadar(){ System.out.println("Animal nadando"); } public void emitirSom(){ System.out.println("Som de animal"); } } public class Cachorro extends Animal { public void comer(){ 51 Modelagem Orientada a Objetos System.out.println("Cachorro comendo"); } public void andar(){ System.out.println("Cachorro andando"); } //sobrecarga do método andar public void andar(int velocidade){ if(velocidade > 10){ System.out.println("Cachorro correndo"); } else{ System.out.println("Cachorro andando"); } } public void emitirSom(){ System.out.println("Au-Au"); } } public class Pinguim extends Animal { public void comer(){ System.out.println("Pinguim comendo"); } public void andar(){ System.out.println("Pinguim andando"); } public void nadar(){ System.out.println("Pinguim nadando"); } } public class Tubarao extends Animal { public void comer(){ 52 Modelagem Orientada a Objetos System.out.println("Tubarao comendo"); } public void nadar(){ System.out.println("Tubarao nadando"); } } public class Teste { /** * @param args */ public static void main(String[] args) { //instancias de classes Animal animal = new Animal(); Cachorro cachorro = new Cachorro(); Pinguim pinguim = new Pinguim(); Tubarao tubarao = new Tubarao(); //animal.andar() faz uma chamada ao método da classe Animal animal.andar(); //animal.voar() faz uma chamada ao método da classe Animal animal.voar(); //cachorro.comer() faz uma chamada ao método da classe Cachorro (sobrescrita) cachorro.comer(); //pinguim.andar() faz uma chamada ao método da classe Pinguim (sobrescrita) pinguim.andar(); //tubarao.emitirSom() faz uma chamada ao método da classe Animal (superclasse) tubarao.emitirSom(); 53 Modelagem Orientada a Objetos } } Atividades e Orientações de estudo Exercícios: Dada a classe Animal: public class Animal { String nome; int idade; private void comer(){ System.out.println("Animal comendo"); } private void andar(){ System.out.println("Animal andando"); } protected void voar(){ System.out.println("Animal voando"); } protected void nadar(){ System.out.println("Animal nadando"); } public void emitirSom(){ System.out.println("Som de animal"); } } » Realize as correções necessárias para que a classe possa ser devidamente estendida por outras classes (subclasses); » Aplique os conceitos de encapsulamento nos atributos da classe, se necessário; 54 Modelagem Orientada a Objetos » Crie uma nova classe de nome Cavalo e sobrescreva os métodos necessários; » Crie uma nova classe de nome Peixe e sobrescreva os métodos necessários; » Na classe Peixe criada, escolha um método para sobrecarregar (justifique sua decisão/escolha); » Crie uma classe Teste, com um método main e realize chamadas ao método sobrescrito das classes Cavalo e Peixe, e realize uma chamada ao método sobrecarregado da classe Peixe. Agora, avalie os seguintes métodos: public void correr(){ System.out.println("personalize a mensagem"); } public void relinchar(){ System.out.println("iHHiiiiiinnnn"); } Em que classes devemos inserir cada um destes? Avalie os cenários. Justifique sua decisão. Após a inserção destes métodos, realize novas chamadas a estes dois métodos a partir da classe main. Agora, para finalizar, represente sua solução através do diagrama de classes UML. Discuta suas soluções com seu tutor, professores e colegas de sala. Compartilhe sua solução no fórum de discussões! Vamos fazer de nosso fórum de discussão a nossa comunidade de POO e Java. 55 Modelagem Orientada a Objetos Considerações Finais Olá, Cursista! Neste volume, conhecemos o conceito de encapsulamento de informações, hierarquia de classes e polimorfismo. Aplicamos e reforçamos diversos conceitos de objetos, classes e modificadores de acesso, aprendidos no Volume 1. Ainda neste volume, vimos diversos exemplos práticos codificados e comentados em Java e realizamos diversas atividades práticas no Eclipse. No próximo volume, conheceremos alguns outros conceitos de orientação a objetos e conheceremos melhor a linguagem Java. Aprenderemos mais sobre o processo de edição, compilação e execução de códigos; variáveis e tipos de dados, operadores aritméticos e lógicos, estruturas condicionais e estruturas de repetição. Bons estudos e até o próximo volume. Aguardamos sua participação no próximo módulo. Até lá e bons estudos! 56 Modelagem Orientada a Objetos Referências [DEITEL, 2006] DEITEL, M. D.; DEITEL, P. J.: C++: Como Programar. 5a. Edição. Pearson. 2006. [DEITEL, 2005] DEITEL, M. D.; DEITEL, P. J.: Java, Como Programar. 6a. Edição. Bookman. 2005. [CORNEL, 2005] CORNEL, G., HORSTMANN C. S.: Core Java 2. Fundamentos. 7a Edição. Alta Books. 2005. [ARNOLD, 2007] ARNOLD, KEN; GOSLING, JAMES: A Linguagem de Programação Java. 4a. Edição.Bookman.2007. 57 Modelagem Orientada a Objetos Conheça os Autores Eduardo Araujo Oliveira http://lattes.cnpq.br/3887722014128939 Possui graduação em Ciencia da Computação pela Universidade Católica de Pernambuco (2005), mestrado em Ciência da Computação pela Universidade Federal de Pernambuco (2006-2008) e atualmente é doutorando pela UFPE. Trabalha como engenheiro de sistemas do Centro de Estudos e Sistemas Avançados do Recife (C.E.S.A.R) em projetos da Motorola desde 2004, tendo experiência com aplicações Java SE e Java ME. Possui certificação Java [SCJP]. Atua como Professor Conteudista no curso de Bacharelado em Sistemas de Informação da UAB/UFRPE. Tem experiência nas áreas de Inteligência Artificial e Educação a Distância, tendo trabalhado e pesquisado com ambientes virtuais de ensino e aprendizado, agentes inteligentes e linguagens de programação. Patrícia Tedesco http://lattes.cnpq.br/7465148175791735 Possui graduação em Ciência da Computação pela Universidade Federal de Pernambuco (1994), mestrado em Ciência da Computação pela Universidade Federal de Pernambuco, na área de Inteligência Artificial Aplicada à Educação (1997) e doutorado em Ciência da Computação - University Of Leeds Computer Based Learning Unit (2001). Atualmente é professora adjunta do Centro de Informática - UFPE. Tem experiência na área de Ciência da Computação, com ênfase em Inteligência Artificial, atuando principalmente nos seguintes temas: SistemasMultiagentes e Atores Sintéticos, Trabalho Colaborativo Apoiado por Computador, Contexto Computacional e Educação a Distância.
Compartilhar