sábado, 10 de maio de 2014

Herança

1. Qual Utilidade? 

          A grande idéia do uso de Herança, é que nos possibilita um Reuso pelo fato de separarmos os elementos (atributos) mais genéricos e abrangentes que costumam ser sempre usados, logo pode-se reaproveitar essa classe para vários diagramas para vários projetos diferentes.
          A Herança também nos proporciona uma melhoria na Manutenção do nosso código, porque se precisarmos acrescentar ou retirar um atributo genérico que pertence a várias classes, alteraremos apenas em um lugar (Superclasse correspondente).
          Segue abaixo um vídeo conceituando bem isso (o vídeo é em inglês).
link caso não funcione: https://www.youtube.com/watch?v=7pM6NqxFMbg

2. O que é: 

     Por que será que o processo se chama 'Herança'?
     Fazendo uma analogia ao que conhecemos, o que é uma herança em nossas vidas? É quando alguém recebe os bens de outra pessoa, geralmente em uma hierarquia familiar.

e O que seria uma 'Herança' em programação? É quando uma classe herda os atributos e comportamentos/métodos (bens) de uma outra classe pré-existente, que pertencem a um mesmo contexto (família), estabelecendo uma relação de 'é um' (a 'Subclasse' é uma 'Superclasse').

2.1 Superclasse e Subclasse 

         Superclasse é a classe sendo estendida/herdada e Subclasse é a classe que estende/herda os atributos e comportamentos.
         Superclasse é a base do objeto, que possui atributos e comportamentos comuns em mais do que uma classe, generalizando-as
          Subclasse é a classe que vai receber os atributos e comportamentos da Superclasse, além de possuir características próprias, especificando-a.

2.2 Cuidado 

           A relação de 'é um', serve apenas como um facilitador para nos mostrar a maioria dos processos de herança, no entanto não se deve usá-lo sem entender o propósito da herança, que é herdar seus atributos e comportamentos. Essa relação funciona melhor quando já sabemos
que uma classe herda da outra, mas estamos em duvida de quem vai ser a Superclasse e quem vai ser a Subclasse.
          Quando se deparar com um código de uma outra pessoa, procure entender para que ele está usando a Herança, pois, nem sempre, somente o nome da classe lhe diz o que ela faz.
          Exemplo real: eu posso criar uma classe Veiculo que tenha o método quantidadePneus(){}, e então criar uma Subclasse Carro que vai herdar Veiculo, usando o 'é um' eu posso perguntar "Carro é um Veiculo?", Veiculo por definição do dicionário significa qualquer meio de transporte, carro se enquadra na definição. Então depois de anos com esse sistema funcionando você entra na empresa sem conhecer o código e o dono da empresa resolveu expandir e incluir veículos marítimos e pede para você implementar ao sistema, então você vai criar a classe Navio e repara que já existe uma classe Veiculo, então se pergunta "Navio é um Veiculo?", pelo português sim, porém fazendo isso a sua classe Navio vai herdar o método quantidadePneus(){}, que não faz sentido para um Navio, fazia sentido apenas anteriormente, quando a empresa operava apenas com Carros, e ai o sistema vira uma 'Emilia' completa. Sem contar que pode haver mais de uma definição para a palavra, mesmo no caso da palavra Veiculo possui mais do que uma definição.
          Exemplo abstrato: eu tenho uma classe Animal que possui o atributo 'sexo' para definir se o animal é macho ou fêmea. Então criaremos a classe Leão e a classe Minhoca, pela pergunta 'é um' ambos são animais, porém a classe Leão herdando o atributo 'sexo' da classe Animal pode me ajudar a separar os machos das fêmeas e fazer o controle que for preciso, logo o processo de Herança me favorece, no entanto para a classe Minhoca, herdar o atributo 'sexo' não me ajuda, sabendo que todas as minhocas são hermafrodita, mesmo que ela seja um animal, o que a classe Animal possui, não contribui em nada para a classe Minhoca.
           Exemplo globalização: suponha que você está encarregado de modificar um código do sistema da sua empresa, mas esse código foi terceirizado e quem fez o código foi alguém que o idioma nativo era algum que possui caracteres totalmente diferentes (Japonês, Chinês, Grego, etc.) e essa pessoa fez o código todo em inglês, porém o nome de algumas classes estavam em seu idioma nativo. Nesse caso não tem como você perguntar se 狼 é um χελώνα. 
Se está pensando "mas isso nunca acontecerá", primeiro que você não tem como saber por quantas pessoas foi feito aquele sistema, algumas podem ter feito somente no idioma deles e posteriormente a maioria foi traduzido; segundo que se pegarmos os exercícios que vocês resolveram das listas da Evelyn, qualquer americano sofreria com esse problema, o que não quer dizer que eles não possam entender o que o código faz, só quer dizer que o nome das variáveis serão interpretadas como nomes genéricos (a, b, c, x, z ...).

3. Herança Múltipla 

NÃO EXISTE HERANÇA MULTIPLA NO JAVA!!!! 

         Herança múltipla é quando uma Subclasse herda os atributos e comportamentos de duas ou mais classes. Esse processo é usado para ser possível combinar características de várias Superclasses existentes como um ponto de partida para a criação da sua nova classe.
         Exemplo: tenho uma classe Carro, que possui os atributos e métodos referentes a quantidade de portas, quantidade de rodas e cor; existe uma outra classe Brinquedo que me diz qual o material do brinquedo. A classe Carro e a classe Brinquedo não possuem relação nenhuma (Carro não é um Brinquedo, Brinquedo não é um Carro).
         Agora eu quero criar uma classe CarrinhoBrinquedo, para controlar as especificações de cada carrinho, as portas do carrinho vão ser fixas ou podem abrir/fechar, as rodas serão fixas ou poderão ser trocadas. Essa classe possui tanto as informações genéricas da classe Carro, quanto as informações da classe Brinquedo além de conter características próprias, logo ela herda de ambas as classes.

3.1 Herança Diamante 

          Esse processo de Herança Múltipla pode gerar um problema, que é chamado de Herança Diamante, que consiste da existência de um polimorfismo em duas ou mais Superclasses de uma mesma Subclasse.
Considere a imagem ao lado, nela indicamos que 'A' é uma Superclasse de 'B' e 'C' que são Superclasses de 'D'.

          A classe 'A' possui o método teste(), e as classes 'B' e 'C' reimplementam esse método teste(), adequando a cada uma. Agora se criarmos um objeto do tipo 'D' e chamarmos o método teste(); qual versão do método é chamado? a versão definida em 'B' ou em 'C'? exatamente, nem o compilador sabe.


Curiosidade: Para corrigir esse tipo de ambigüidade, cada linguagem que aceita Herança Múltipla possui uma maneira de indicar qual usar. 
Exemplo: na Linguagem C++ eu posso escrever da seguinte forma D extends B with C -> a implementação de teste() em C vai ser usada ou D extends C with B -> a implementação de teste() em B vai ser usada.

4. No Diagrama de Classes

A Herança no diagrama é representada de acordo com a imagem abaixo. 

A seta 'fechada e branca' está representando que Funcionario é a Superclasse e Diretor, Professor e Administrativo são Subclasses de Funcionario.

5. No java 

5.1. Criação

             Para indicarmos uma Herança, utilizamos o comando extends indicando quem herda de quem, ou seja, public class A extends B representa que a classe 'A' herda o conteúdo da classe 'B'.

5.2 Construtor

             O construtor serve para instanciar objetos de uma classe, ou seja, para que possamos criar dois ou mais objetos com as mesmas características, mas que não são o mesmo objeto (crio dois objetos de TV, mas uma tem 15 polegadas e a outra 30 - possuem a mesma característica de tamanho, porém não são o mesmo objeto).
              O construtor é uma função que possui o mesmo nome da classe, podendo inicializar atributos a partir de parâmetros, não possui retorno. A classe pode possuir mais do que um construtor, mas deve conter ao menos um.
sintaxe: public Classe(tipo parametro){} 
              Exemplo: public Pessoa(String parametroDeNome){} pode ser feito sem parâmetro ficando public Pessoa(){}.
              Na criação do Construtor de uma Subclasse, precisamos indicar a construção com a Superclasse, para isso utilizamos dentro da execução do Construtor a sintaxe super();.
Exemplo:
public class Juridico extends Pessoa{
            public Juridico(){
                      super();
            }
}

5.3 Acesso

             Para instanciarmos um objeto usamos Classe objeto = new Contrutor(); continuando o exemplo acima ficaria Pessoa objPessoa = new Pessoa(); , agora que temos o objeto, para acessarmos os métodos referentes a classe Pessoa, utilizamos o '.' depois do objeto indicando que estou 'entrando' na classe para chamar algo, e cada '.' se refere a algo dentro da classe anterior, ou seja, eu posso acessar da seguinte forma objPessoa.getNome().toUpperCase(); estou dizendo que o objPessoa acessa a classe Pessoa, chama o método getNome() que retorna uma String que é uma outra classe e que portanto possui alguns métodos, que no caso está acessando na classe String o método toUpperCase() .
             Para controlar o acesso são utilizados os Modificadores (public, private, protected), na qual public permite que todos acessem, private somente a classe em que foi declarada e protected podem ser acessados dentro do pacote ou pelas Subclasses. Se não colocar nada significa que tem acesso 'default' (também chamado de package private, o modificador tímido) que só pode ser acessado dentro do pacote em que foi declarado.
Caso seja necessário  especificar dentro da Subclasse o que é referente a ela ou o que é referente a Superclasse, utilizamos o this, para indicar que é referente a essa classe, e super, para indicar que é referente a Superclasse (é utilizado quando temos ambigüidade ao código, ou seja, quando possui o mesmo nome para duas coisas diferentes).

5.4 Curiosidades:

  • Uma classe não pode ser Abstract e Final ao mesmo tempo, de modo simples, Abstract existe para ela ser 'estendida' e Final diz que ninguém pode 'estender' essa classe, logo seus princípios são contraditórios, não fazendo sentido ser os dois tipos.
  • Você pode criar métodos 'abstract', mas eles só funcionam se a classe for 'abstract' e nas subclasses que também sejam 'abstract', caso a subclasse não seja 'abstract' (sendo concreta) você precisa criar esse mesmo método da Superclasse.
  • É possível redefinir a visibilidade/acesso de métodos herdados (private, protected, public), mas sempre empatando ou aumentando a visibilidade, e nunca diminuindo. Sendo private a menor visibilidade (somente a própria classe) e public a maior visibilidade.
  • O "tipo de variável" de uma Subclasse servem como parâmetro de um "tipo" da Superclasse, porém só podemos chamar os métodos do tipo escolhido
            Ex.:      public class X (Superclasse)

                        public class Y extends X (Subclasse de 'X')


                        Y objeto1 = new Y();


                        public void metodoQualquer(X parametro){}

            Sabendo que existe meu 'objeto1' do tipo 'Y' e meu 'metodoQualquer' que recebe um parâmetro do tipo 'X', eu posso executar esse método usando meu 'objeto1' como parametro -> metodoQualquer(objeto1); No entanto dentro do método 'metodoQualquer' só podemos utilizar as propriedades do tipo 'X' que é o que eu garanto que vai existir.

Parte de texto sobre herança

texto1:

    Herança é um mecanismo que permite, a partir de classes com comportamento comum, abstrair características comuns a todas e centralizá-las em uma classe-base ou superclasse.
     A partir de uma superclasse, podem ser especificadas outras classes (subclasses), sendo que uma subclasse pode herdar de (estender) apenas uma superclasse diretamente. Tal herança consiste em uma subclasse receber as características (atributos e métodos) da superclasse. No entanto, ela também pode ser acrescida de outros elementos que não constem de superclasse. Construtores não são herdados.
    É fundamental compreender como criar objetos a partir de subclasses, como manipular objetos criados a partir de subclasses e como funcionam as restrições de acesso aos membros das superclasses.
    Apesar de ser um conceito sofisticado, a herança, na realidade, é usada em todas as aplicações Java, mesmo que o programador não explicite sua utilização. Isso ocorre porque, quando se cria uma classe sem qualquer referência a uma superclasse, o próprio compilador insere na classe criada uma relação de herança direta com a classe java.lang.Object, tais como equals() e toString().
    A capacidade de herança garante altos índices de reaproveitamento de código, permitindo uma melhor componentização.

Retirado do livro:
Entendendo e Dominando o Java - 3a Edição. Editora Digerati; October 1, 2009. Authors: Oziel Moreira Neto. ISBN - 9788578730888

texto2:

A herança é o mecanismo de derivação através do qual uma classe pode ser construída como extensão de outra. Neste processo, todos os atributos e operações da classe base passam a valer, também, para a classe derivada, podendo esta última definir novos atributos e operações que atendam suas especificidades.
Uma classe derivada pode, também, redefinir operações de sua classe base, o que é conhecido como uma operação de sobrecarga.
O modelo de Orientação a Objetos coloca grande ênfase nas associações entre classes, pois são estas que estabelecem os caminhos para navegação, ou troca de mensagens, entre os objetos que as representam.

Retirado do pdf :
http://neerci.ist.utl.pt/neerci_shelf/LEIC/2%20Ano/1%20Semestre/Programacao%20com%20Objectos/Bibliografia/Programa%E7%E3o%20Orientada%20a%20Objectos.pdf

Vídeos

Roberto Perillo:



XTI aula 47 e 48:




Exercicio de Exemplo

Implemente o diagrama abaixo:

Resolução:



A Herança é feita a partir do 'extends', criando a possibilidade de quando acessamos um objeto de uma Subclasse nos mostre o conteúdo de ambas as classes envolvidas.

Exercicio Teorico Praticando

            Fixação de conceitos em 3 etapas (Item A, B e C do exercício)

O diagrama da Figura 1.1 fornece um indicativo da evolução das estrelas (extraído de http://htmlimg4.scribdassets.com/1o21vtrh1c27o6fc/images/1-9a1f1e25d0.png ):



 
Tendo em vista a Figura 1.1, criar a hierarquia de classes dada na Figura 1.2:

Item (A): O método mostrarTipo() deverá mostrar o nome da classe, o método mostrarDados() deverá retornar o conteúdo de cada um dos campos (devidamente inicializados por construtores apropriados) e o campo nome deverá conter o nome do objeto (por exemplo, o nome da estrela do nosso Sistema Solar é "Sol").
Item (B): Modificar a classe ProtoEstrela de modo que seus campos sejam private, bem como elaborar métodos set e get para modificar e retornar os valores contidos nos mesmos. Observe que esta modificação faz com que a classe EstrelaAmarela não tenha mais acesso direto aos campos declarados na classe ProtoEstrela, sendo, portanto, necessário empregar os métodos set nos construtores de EstrelaAmarela para inicializar temperatura, magnitude e luminosidade.
Item (C): Modificar a classe ProtoEstrela de modo que o construtor sem parametros use o construtor com parametros por meio da palavra-chave this. Modificar, também, a classe EstrelaAmarela de modo que seus construtores empreguem os construtores da classe ProtoEstrela por meio da palavra-chave super.
Observação Importante: O uso das palavras-chave this e super irá funcionar independente do modificador de acesso nos campos da superclasse ser protected ou private. Isto decorre do fato de que super chama o construtor da superclasse e este tem total acesso aos campos.

Resolução:


Item (A)



Item (B)

Item (C)

Exercicios Praticos



Referências Bibliográficas

http://ns1.facape.br/jocelio/p3/material_em_pdf/OOHeranca.pdf
http://ccsl.ime.usp.br/files/books/intro-java-cc.pdf
http://www.ruirossi.pro.br/livros/li-rui-pcj-cap14.pdf

DEITEL & DEITEL. Java – como programar. 4a Edição, Bookman, 2003.

FURGERI, SÉRGIO – Java 2 Ensino Didático. Editora Érica, 2002. 

SIERRA, KATHY & BATES, BERT. JAVA 2 – Certificação SUN – Programador e 
desenvolvedor. 2ª Edição, AltaBooks



Grupo: 

Daniel Luz
Gabriel Hiroyuki
Marina Mendez

3 comentários: