E aí, pessoal! Tudo certo? Nesse artigo vamos ver sobre composição no Java, o que é e também como funciona. Vamos lá?

Antes de mais nada a composição é uma forma de descrever referência entre duas ou mais classes usando uma variável de instância.

Da mesma forma ela também pode ser interpretada como um objeto que é composto por outro, ou até mesmo outros objetos.

Logo, a composição é fortemente usada para reaproveitamento de código, onde você pode ter uma classe que será composta por outras classes, e essas outras classes que compõem ela também podem fazer parte da composição de outras inúmeras classes, claro, desde que faça sentido.

Por que usar composição?

De acordo com Joshua Bloch, que explica na 3ª edição de seu livro Effective Java, a principal razão para usar composição é que ela permite reutilizar código sem modelar uma associação (É um) como você faz usando herança, assim permitindo um encapsulamento mais forte e tornando seu código mais fácil de manter.

O que é a composição?

Primeiramente, a composição nada mais é do que, uma classe composta por uma ou mais classes dentro dela. Além disso, outras classes não podem existir sem o proprietário ou a classe pai, do mesmo modo que uma classe Carro é uma composição de Motor e Pneus.

Então, seguindo esse pensamento é bem fácil de assimilarmos em todos os exemplos.

Vamos seguir esse exemplo de Carro que será a classe pai e será composta por diversas outras classes usando a composição.

Vamos ter uma classe Carro e ela vai ser composta por outras classes, tentando replicar um cenário real de um carro sendo composto por diversos outros mecanismos.

Dessa forma como a classe Carro possuirá diversos atributos, mas somente alguns serão dela mesma, o restante será feito através da composição.

Nosso objetivo é ter os atributos de um carro, porém, se criarmos campos específicos para cada item que o carro tem na própria classe de Carro, vai ficar muito extenso, fora que, dessa forma não é possível reaproveitar o código nele escrito.

Portanto, ao invés de termos uma classe Carro que irá possuir modelo da bateria e carga da bateria nós iremos ter um objeto do tipo Bateria e ela por sua vez vai possuir modelo e carga.

Em conclusão, é dessa forma que funciona a “mágica” da composição!

Exemplos no código:

Nós temos as seguintes classes:

Bateria:

public class Bateria {
   String modelo;
   String carga;
}

Parafuso:

public class Parafuso {
    Double tamanho;
    Double peso;
}

Porta:

public class Porta {
    void abrir(){
        System.out.println("Abrindo porta");

    }
    void fechar(){
        System.out.println("Fechando porta");

    }
}

Motor:

public class Motor {
    String modelo;
    String potencia;
    ArrayList<Parafuso> parafusos;
}

Colocando em prática

Antes de tudo, notamos que até aqui são simplesmente classes normais, algumas contendo atributos, e a classe porta contendo métodos.

Mas agora, vamos partir para a implementação da composição, onde nós usamos uma palavrinha chave pra detectar quando a composição é viável, e faremos a comparação usando TEM UM da seguinte forma:

Um Carro TEM UM(A) Bateria? Sim.

Um Carro TEM UM(A) Parafuso? Sim, até mais de um.

Um Carro TEM UM(A) Porta? Sim, até mais de uma.

Ao contrário da herança que nós comparamos usando É UM, identificamos assim, onde é viável a composição.

Vamos partir usando essas classes para compor nosso Carro.

Após usarmos a regra TEM UM, iremos fazer a composição da nossa classe Carro usando essas classes acima.

Carro:

public class Carro {
    String modelo;
    String placa;
    String qtdDeLugares;
    
    Motor motor; //Carro tem um Motor
    Bateria bateria; //Carro tem uma Bateria
    ArrayList<Porta> portas; //Carro tem Portas.

Antes de mais nada, nós criamos um Carro e ele é composto por variáveis de instância de (Motor, Bateria e Porta), e também temos 3 atributos normais(modelo, placa, qtdDeLugares).

Do mesmo modo que, a partir de uma instância de Carro podemos usar os métodos e atributos das composições de Carro, por exemplo, nós podemos usar o método abrir() que é um método localizado na variável de instância de cada porta da nossa lista de portas e assim por diante.

Vamos fazer um teste no próprio código?

Criando uma classe de teste e instanciando um motor:

public class Teste {
    public static void main(String[] args) {
        Carro carro = new Carro();

        carro.portas.get(0).abrir(); // Chamando o método abrir da    porta cujo index é 0
	Sy stem.out.println(carro.motor.potencia); // Imprimindo a potencia do motor 
        System.out.println(carro.modelo); // Imprimindo o modelo do carro
    }

}

Dessa forma, observe que acima nós conseguimos acessar os métodos e atributos das variáveis de instâncias dentro de Carro, e até mesmo os atributos e métodos dentro dos atributos das próprias variáveis de instância.

Também podemos fazer a atribuição de valores nesses atributos, como vemos a seguir:

public class Teste {
    public static void main(String[] args) {
        Carro carro = new Carro();

        carro.portas.add(new Porta());
        carro.motor.potencia = "1.200c";
        carro.modelo = "Bugatti Veyron Super Sport";
    }

}

Portanto…

Agora no ultimo exemplo estamos adicionando valores aos atributos, e finalizando essa parte. Acredito que o conceito da composição esteja bem fixado, portanto vamos adicionar um pouco mais de complexidade e usar atributos privados, que é o que mais usamos no dia a dia.

Posteriormente, depois que trocarmos nossos atributos para privados nosso código do exemplo acima, ele deve ficar dessa forma:

public class Teste {
    public static void main(String[] args) {
        Carro carro = new Carro();

        // carro.portas.add(new Porta());
        carro.getPortas().add(new Porta());

        // carro.motor.potencia = "1.200c";
        carro.getMotor().setPotencia("1.200c");

        // carro.modelo = "Bugatti Veyron Super Sport";
        carro.setModelo("Bugatti Veyron Super Sport");
    }

}

Assim é feita e usada a tão falada e temida composição. Simples, não? Afinal, são apenas objetos formados por outros objetos, ou se você também quiser falar, são Classes compostas por outras Classes.

Conclusão

Dessa forma eu espero realmente ter agregado algo no conhecimento de vocês. Espero que gostem do artigo, um abraço e até a próxima! =D

Veja também…

Herança de Classes em Java

Curso Padrões de Projeto em JAVA na Prática!