Enviar um café pro programador

Pode me ajudar a transformar cafeína em código?
Mostrando postagens com marcador Herança. Mostrar todas as postagens
Mostrando postagens com marcador Herança. Mostrar todas as postagens

Apostila de Java, capítulo 07 - Herança, reescrita (override) e polimorfismo

Neste tutorial de Java de nosso curso, iremos resolver as questões propostas na apostila de Java da Caelum.
Especificamente, o capítulo 7, que trata de assuntos como Herança e Polimorfismo, conceitos muito importantes e essenciais sobre Orientação à Objetos.

Interface em Java (implements) - O que é, para que serve e como implementar

Iremos agora estudar um assunto muito importante em nossa apostila de Java, que irá usar principalmente, dentre outras coisas, os conceitos aprendemos sobre Classes e Métodos Abstratos, as interfaces.

Aprenderemos também uma importante palavra reservada do Java, o implements.

Herança ou Composição: Qual o melhor?

Acabamos de estudar a Herança, que assim como a Composição, é uma forma de tratar a relação entre os objetos, como eles devem ser vistos e trabalhados.

Talvez agora, como iniciante em nossa apostila de Java, isso não seja motivo de muita preocupação para você, mas certamente no futuro será. E para melhor esclarecer isso, nossa apostila de Java irá falar mais sobre as vantagens e desvantagens de cada uma dessas técnicas.

Herança de construtores e Override

Agora que você já sabe o que é herança, sua importância, quando usar e viu vários exemplos práticos do mundo real, vamos mostrar como fazer uma classe herdar as características de outra.

Nesse tutorial de Java ensinaremos também a relação dos construtores com as superclasses e subclasses, e como usar o tão importante @Override.


Herança em Java - o que é, para que serve, exemplos e quando usar

Chegamos em um ponto muito importante em nosso curso de Java no que se refere a Programação Orientada a Objetos.
Herança é uma das maiores características desse tipo tão importante e usado tipo de programação.

Através desse recurso, você irá criar classes de uma maneira bem mais rápida, eficiente e fácil de manter: baseando classes em outras.

Composição: trocando informações entre objetos

Um dos melhores artifícios do Java é a comunicação entre seus elementos, variáveis, métodos, objetos, classes e coisas que verá mais adiante. Mais que isso, o bacana é que podemos controlar essa comunicação, ela pode ser: pública, privada e protegida.

Nesse tutorial, daremos início a essa comunicação, falando sobre a Composição (Composition), que é simplesmente o ato de passar um objeto para outro, para usar seus métodos ou atributos.

O que é Composição em Java

É instanciar, ou usar, uma classe/objeto em outra(o). É como se elas se comunicassem, trocassem informações. Ou seja, serve para reutilizar dados, sem ter que criar mais código pra isso.
Simplesmente passamos a informação - na forma de Objeto - para outro Objeto, e este se encarrega de obter os dados e como trabalhar em cima dele.

Costuma-se dizer que composição é o ato de delegar trabalho para outro objeto.
Isso deixa seu código mais elegante, menor e mais seguro.


Para que serve a Composição em Java

Como citamos em nosso artigo introdutório sobre Classes e Objetos, a comunicação entre seus dados é essencial.
Talvez não note muito essa necessidade em projetos pequenos e de iniciantes, mas quando for um profissional, vai ter muita dor de cabeça com isso. Através de uma simplificação de projetos reais, vamos mostrar exemplos de códigos e passaremos exercícios para você notar a importância da Composição em aplicações Java.

Demos o exemplo de setores diferentes em uma empresa naquele artigo inicial.
Dificilmente uma empresa de grande porte vai mandar você fazer e ter acesso a todo o sistema, principalmente o setor financeiro.
Geralmente esse é mantido à sete chaves. Mas como expliquei lá, eles podem simplesmente compartilhar certos dados com você, como o salário final de cada funcionário, para você usar em sua classe "Funcionario".
Notou? Você criar sua classe, faz seu projeto e usa dados de outro Objeto/Classe. E o mais importante: é seguro! Você não faz a mínima idéia do que aconteceu lá, de como é calculado as coisas, dos segredos financeiros da empresa etc.

Graças a orientação a objetos - e outras coisas - isso é possível. Assim você não precisa repetir código.
Além da segurança, a Composição em Java faz com que não seja necessário repetir código. Você simplesmente usa o que já foi feito em outra Classe/Objeto, como é o caso do exemplo da empresa.
Imagina se o programador não soubesse Java? Ia ter que repetir todo o código do setor financeiro dentro da classe "Funcionario"?
Acredite, há coisas bizarras sendo feitas por aí.


Herança x Composição

Mais a frente, em nosso curso online de Java, iremos falar sobre uma das mais importantes, e controversas, e usadas funcionalidades do Java: a Herança. Isso nos leva ao encapsulamento de dados.
Não vamos entrar em muitos detalhes agora, mas basicamente herança é capacidade de uma classe herdar dados de outra.
Por exemplo, você cria uma classe mãe. Quer criar uma classe parecida com a mãe - mas com outras funcionalidades, você não precisa reescrever tudo. Basta fazer com que a classe filha herde a classe mãe.

Por exemplo, podemos criar a classe "Carro" quem atributos como "motor", "portas", "carburador" etc, pois todos atributos estão presentes em todos carros. Fazemos então a classe "Fusca" e a classe "Ferrari" herdar a classe "Carro".
Ora, é claro que vamos adicionar mais funcionalidades na classe "Ferrari", pois ela possuir mais atributos que o padrão genérico generalizado da classe "Carro". Mas não deixa de ser um carro.

Essa generalização, o fato de algumas classes herdadas não precisarem de todos os atributos da classe mãe, também devido ao fato de ao se mudar a classe mãe mudar todas as classes filhas e uma porção de outros detalhes, faz com que herança seja um conceito perigoso e não recomendado. Alguns simplesmente abominam a herança.
Não entraremos em detalhe agora, mas usar Composição é inofensivo e bem mais recomendado. Porém, cada caso é um caso.



Exemplo de uso de Composição em Java

Exercício: Descobrindo se um Funcionário chegou atrasado e seu tempo de trabalho. 

Nesse exemplo, vamos criar 2 classes adicionais: "Funcionario" e "Hora"

Vamos criar um funcionário, o 'geddyLee', criar um objeto para armazenar a hora que ele chegou 'horaChegada' e a hora que ele saiu 'horaSaida'.

A partir da hora de chegada, vamos verificar se ele chegou atrasado (após as 8h) e usando informações dos dois objetos da classe "Hora", vamos saber quanto tempo ele trabalhou e armazenar essa informação na variável "tempoTrabalhado", do objeto 'geddyLee' da classe "Funcionario", e vamos guardar a informação caso ele tenha chegado atrasado

Ou seja, vamos trocar bastante informações entre esses objetos !

controleHorario.java

Essa é nossa classe principal, que tem o método main.
Na main, simplesmente criamos os objetos de Hora e Funcionário mencionados no enunciado.
Iniciamos os objetos de "Hora" já com seus valores (hora, minuto,segundo). Você pode mudar a seu gosto, para testes ou pedir ao usuário, através da classe Scanner.

A seguir, a título de informação, ele exibe a hora de chegada, de saída e o tempo total trabalhado em horas.
A main é bem pequena e enxuta, como deve ser.


Hora.java

Essa classe recebe três elementos inteiros: horas, minutos e segundos, e faz um tratamento.
O tratamento é: as horas devem ser inteiros entre 0 e 23, os minutos e segundos devem ser inteiros entre 0 e 59.

Caso não seja, é lançada uma excessão (artíficio para mostrar que ocorreu um erro e a aplicação é encerrada).
Experimente colocar uma data errada para ver a mensagem de erro.

Os métodos dessa classe são simples getters um toString().

Método toString()
O método toString é um método especial, existente em todos os objetos de Java (pois está na classe Objects e todas classes são derivadas desta).

Como o nome pode sugerir, ele serve para retornar uma String.
Vamos formatar uma string com argumentos, por isso vamos usar o método format, para exibir as horas, minutos e segundos no formato: hh:mm:ss

Uma outra característica especial deste método é que ele se torna o padrão e automaticamente invocado, caso tente imprimir um 'objeto'.
Isso mesmo, se colocar apenas um objetos em uma função de print, esse método será invocado.

Por isso , para imprimir na main, fizemos apenas:
System.out.println("Hora de chegada: " + horaChegada);
System.out.println("Hora de saída: " + horaSaida);

Mas poderíamos ter feito:
System.out.println("Hora de chegada: " + horaChegada.toString());
System.out.println("Hora de saída: " + horaSaida.toString());


Funcionario.java

Essa classe que vai recebe a informação de outros objetos. No caso, ela recebe objetos da classe "Hora".
Vamos comentar seus métodos:


  • public double tempoAtraso(Hora horaChegada)
Vamos descobrir o tempo que o funcionário atrasou convertendo a hora de chegada em segundos.
Simplesmente transformamos a hora em que o funcionário chegou em segundos:
horaChegada.getHour()*60*60 + horaChegada.getMinute()*60 + horaChegada.getSecond()
E subtraímos do tempo que ele deveria chegar na empresa (8h00min):
8*3600.0
E dividimos por 3600.0, para o resultado ser um double que representa as horas atrasadas.


  • public double horasTrabalhadas(Hora horaChegada, Hora horaSaida)
Para o cálculo do tempo trabalhado de um funcionário, vamos levar em conta somente as horas trabalhadas.

Primeiro, vamos transformar a hora da saída e a hora da chegada em minutos e subtrair esse valor:
(horaSaida.getHour()*60 + horaSaida.getMinute()) - (horaChegada.getHour()*60 + horaChegada.getMinute())
Agora temos a diferença entre os horários de chegada e saída, em minutos.
Então, dividimos tudo por 60.0 para ter o tempo trabalhado, em horas.

Caso esse tempo seja negativo, é porque você colocou uma data de saída anterior a data de chegada.
Então, um erro, com a explicação, é lançado e aplicação é encerrada.


  • public double getHorasTrabalhadas()
Um simples exemplo de get, que retorna a variável 'tempoTrabalhado'.



Código do nosso programa:

controleHorario.java

public class controleHorario {

    public static void main(String[] args) {

        Hora horaChegada = new Hora(8, 0, 1);
        Hora horaSaida = new Hora(9, 30, 0);
        Funcionario geddyLee = new Funcionario("Geddy Lee", horaChegada, horaSaida);
        
        System.out.println("Hora de chegada: " + horaChegada);
        System.out.println("Hora de saída: " + horaSaida);
        System.out.printf("Horas trabalhadas: %.1f\n",geddyLee.getHorasTrabalhadas());
        

    }

}

Hora.java

public class Hora {
    private int hours,
                minutes,
                seconds;
    
    public Hora (int hours, int minutes, int seconds){
        //preenchendo as horas
        if(hours>=0 && hours <24 )
            this.hours = hours;
        else
            throw new IllegalArgumentException("Hora inválida");
            
        //preenchendo os minutos
        if(minutes >=0 && minutes < 60)
            this.minutes = minutes;
        else
            throw new IllegalArgumentException("Minutos inválidos");
        
        //preenchendo os segundos
        if( seconds >=0 && seconds < 60)
            this.seconds = seconds;
        else
            throw new IllegalArgumentException("Segundos inválidos");
            
                
    }
    
    @Override
    public String toString(){
     return String.format("%d:%d:%d", getHour(), getMinute(), getSecond());
    }
    
    public int getHour(){
        return this.hours;
    }
    
    public int getMinute(){
        return this.minutes;
    }
    
    public int getSecond(){
        return this.seconds;
    }
    
}


Funcionario.java

public class Funcionario {
    private String nome;
    private boolean atraso;
    private double tempoTrabalhado, tempoAtraso;
    
    public Funcionario(String nome, Hora horaChegada, Hora horaSaida){
        this.nome=nome;
        this.tempoAtraso = tempoAtraso(horaChegada);
        
        if(this.tempoAtraso > 0)
            this.atraso=true;
        
        if(atraso){
            System.out.println("Funcionário '" + this.nome + "' atrasado. ");
        }
        
        this.tempoTrabalhado = horasTrabalhadas(horaChegada, horaSaida);
    }
    
    public double tempoAtraso(Hora horaChegada){
        return ((horaChegada.getHour()*60*60 + horaChegada.getMinute()*60 + 
                 horaChegada.getSecond()) - 8*3600.0)/3600.0;
    }
    
    public double horasTrabalhadas(Hora horaChegada, Hora horaSaida){
        double horas = ( (horaSaida.getHour()*60 + horaSaida.getMinute()) - 
                       (horaChegada.getHour()*60 + horaChegada.getMinute()) )/60.0;
        
        if(horas < 0)
            throw new IllegalArgumentException("Hora de saída anterior a hora de chegada");
        
        return horas;
    }
    
    public double getHorasTrabalhadas(){
        return this.tempoTrabalhado;
    }
}



Exercício: Aplicativo Java para um Supermercado

Você foi selecionado para criar um aplicativo - em Java, claro - para um supermercado.
O que o dono do estabelecimento pediu a funcionalidade "Promoção para você", que funciona da seguinte maneira:
Após as 20h, todos os produtos recebem um desconto de 10%.
Aos sábados e domingos esse desconto vale o dia inteiro.

Ou seja, além de ter uma classe para os produtos do supermercado, você deve criar outra com o horário da compra.
Use a técnica de composition para passar o objeto referente ao horário da compra para o objeto referente ao produto que está sendo comprado. Assim, no objeto produto o preço é calculado com base no horário e dia da semana.

Na sua main, peça o preço do produto, dia da semana e horário da compra (hora, minuto e segundos), e devolva o valor final do produto com base naquele horário.

PS: Em uma aplicação real, não seria necessário fornecer esses dados. Eles seriam obtidos por um leitor de código de barras para saber o preço do produto, e pegaria o horário do sistema, pra preencher os dados referentes ao horário.
Pedimos, porém, por questão de aprendizado, já que você não deve ter um leitor desses em casa...

Contribuir com o Java Progressivo

Que tal apoiar e fazer crescer o ensino da programação no Brasil ?

Ajudar nosso país a crescer e se desenvolver cada vez mais, tecnologicamente?

Clica abaixo pra saber mais!

Apoiar o Projeto Progressivo