Enviar um café pro programador

Pode me ajudar a transformar cafeína em código?
Mostrando postagens com marcador Questão resolvida. Mostrar todas as postagens
Mostrando postagens com marcador Questão resolvida. Mostrar todas as postagens

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...

Aplicativo: Simulação simples de conta bancária


Aplicativo: Conta bancária/Caixa eletrônico simples em Java

Crie um protótipo de caixa eletrônico na linguagem de programação Java. No início, ele pede seu nome e valor $$ inicial que tem na conta. O programa deve fornecer um número de até 4 dígitos - número da conta - para o usuário (use Random). Esses dados serão usados para criar um objeto da classe "Conta.java"

A seguir, mostra um menu com as opções (esse menu deverá ser um método):
- Extrato: exibe o nome, número da conta, saldo e quantos saques já foram realizados
- Sacar: recebe o valor a ser sacado, informa se pode ser sacado (não pode ficar negativo) e mostra o saldo
- Depositar: recebe o valor a ser depositado e mostra o novo saldo
- Sair

Esse menu aparece até o usuário escolher sair. As outras opções são métodos que devem fazer parte da "Conta.java" (setters e getters). Note que o usuário pode sacar no máximo 5 vezes por dia.


Exercício: Método que recebe um número qualquer de argumentos (...)

Exercício resolvido e comentado em Java:
Um professor, muito legal, fez 3 provas durante um semestre mas só vai levar em conta as duas notas mais altas para calcular a média.
Faça uma aplicação em Java que peça o valor das 3 notas, mostre como seria a média com essas 3 provas, a média com as 2 notas mais altas, bem como sua nota mais alta e sua nota mais baixa. Essas médias devem ser calculadas usando o mesmo método, pois você é um programador Java e não vai ficar criando métodos à toa.
Crie um método que receba as 3 notas e retorna a maior delas. E outro que retorna a menor.

Aplicativo: menu simples usando métodos, laços e o comando switch

Usando um método para exibir um menu de opções

Menu simples usando métodos, laços e o comando switch em JavaFocando o objetivo de nosso curso, que é fazer e mostrar coisas úteis, vamos mostrar uma utilidade de métodos que simplesmente exibem mensagens na tela.



Programa em Java: Como criar um menu

Vamos usar o exercício 9, sobre saídas simples (Clique aqui para ver a questão).
Basicamente, vamos usar nossos conhecimentos em laços (do ... while), o comando switch (para escolher entre as opções do menu) e 5 métodos.
Um método para cada opção (inclui, altera, exclui, consulta) e outro método que mostra esse menu de opções.

Como as opções são números, usaremos um tipo inteiro, chamado 'opcao', para receber as opções do usuário.

Como queremos que o menu seja exibido ao menos uma vez, usamos o do...while.
Ao entrar nesse laço, o menu é exibido com o comando 'menu();' que chama o método que exibe o menu.
Logo após, o programa espera a entrada do usuário. Dependendo do que foi digitado, o método específico - inclui(), altera(), exclui() ou consulta() - é selecionado pelo switch.
O programa só termina se o usuário digitar 0.


import java.util.Scanner;

public class menu {
    
    public static void menu(){
        System.out.println("\tCadastro de clientes");
        System.out.println("0. Fim");
        System.out.println("1. Inclui");
        System.out.println("2. Altera");
        System.out.println("3. Exclui");
        System.out.println("4. Consulta");
        System.out.println("Opcao:");
    }

    public static void inclui(){
        System.out.println("Você entrou no método Inclui.");
    }
    
    public static void altera(){
        System.out.println("Você entrou no método Altera.");
    }
    
    public static void exclui(){
        System.out.println("Você entrou no método Exclui.");
    }
    
    public static void consulta(){
        System.out.println("Você entrou no método Consulta.");
    }
    
    public static void main(String[] args) {
        int opcao;
        Scanner entrada = new Scanner(System.in);
        
        do{
            menu();
            opcao = entrada.nextInt();
            
            switch(opcao){
            case 1:
                inclui();
                break;
                
            case 2:
                altera();
                break;
                
            case 3:
                exclui();
                break;
                
            case 4:
                consulta();
                break;
            
            default:
                System.out.println("Opção inválida.");
            }
        } while(opcao != 0);
    }
}

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