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


