O Poder da Classe Enum com métodos abstratos
Tags: java, cleancode, springboot, enum
Published: 2022-03-30 02:19:33

Ferramentas necessárias:
* [Java SDK](https://www.oracle.com/java/technologies/downloads/)
* Ide de sua preferencia

Bora galera para mais um post onde vou detalhar uma forma de utilizar a classe Enum para deixar seu código mais limpo e mais fácil de entender.
Vamos criar uma aplicação Springboot que ira cadastrar colaboradores de uma empresa (nome, cargo, bonificação), vamos utilizar o poder da classe Enum e dos métodos abstratos para gerar o salario do colaborador mais a bonificação do colaborador conforme o seu cargo. 
Para iniciarmos crie seu projeto Spring através do site [Spring Initializr](https://start.spring.io/) conforme imagem abaixo
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n0ly0i8rceda2fgsv430.png)
Vamos configurar nosso banco de dados H2, em application.properties coloque as seguintes configurações.
```
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
```
Nesse artigo o foco e mostrar como podemos utilizar a classe Enum com métodos abstratos para atingir uma regra de negocio e manter um código limpo, portanto não iremos nos preocupar com design patterns ou estrutura de códigos blz.
Dito isso criamos nossa classe Colaborador que será nossa Entity e a classe Enum TipoCargo.
**Colaborador**
```
package com.example.demo;

import javax.persistence.*;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Positive;

@Entity
public class Colaborador {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank
    private String nome;

    @NotBlank
    private TipoCargo cargo;

    @NotBlank
    @Positive
    private Double salario;

    @Deprecated
    public Colaborador() {
    }

    public Long getId() {
        return id;
    }

    public String getNome() {
        return nome;
    }

    public TipoCargo getCargo() {
        return cargo;
    }

    public Double getSalario() {
        return salario;
    }

    public Colaborador(String nome, TipoCargo cargo, Double salario) {
        this.nome = nome;
        this.cargo = cargo;
        this.salario = salario + cargo.bonificacaoColaborador(salario);
    }

    @Override
    public String toString() {
        return "Colaborador{" +
                "id=" + id +
                ", nome='" + nome + '\'' +
                ", cargo=" + cargo +
                ", salario=" + salario +
                '}';
    }
}
```

**TipoCargo**
```
package com.example.demo;

public enum TipoCargo {
    GERENTE{
        @Override
        public double bonificacaoColaborador(Double salario) {
            return salario * 0.1;
        }
    },
    SUPERVISOR{
        @Override
        public double bonificacaoColaborador(Double salario) {
            return salario * 0.20;
        }
    },
    AJUDANTE{
        @Override
        public double bonificacaoColaborador(Double salario) {
            return salario * 0.50;
        }
    },
    DEV{
        @Override
        public double bonificacaoColaborador(Double salario) {
            return salario * 0.70;
        }
    };

/* metodo abstrato recebe o salario do colaborador parametro*/
    public abstract double bonificacaoColaborador(Double salario);
}
```
E aqui que a magica acontece, veja que em nossa classe Enum TipoCargo criamos um método abstrato **bonificacaoColaborador** que será por obrigação implementado por cada enum de nossa classe.
Este método recebe o salario do colaborador como parâmetro e retorna a porcentagem desse salario conforme o cargo especificado no enum.
Já na classe Colaborador quando passamos os valores para criar um novo colaborador, através do constructor, o salario e calculado utilizando o enum passado no corpo da requisição para chamar o método **bonificacaoColaborador** que será implementado conforme o valor desse enum.
Vamos criar agora as classes, ColaboradorRepositoy, ColaboradorController e ColaboradorForm para testarmos nossa aplicação via Postman.
**ColaboradorRepository**
```
package com.example.demo;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ColaboradorRepository extends JpaRepository<Colaborador,Long> {
}
```
**ColaboradorController**
```
package com.example.demo;

import org.springframework.http.HttpEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class ColaboradorController {

    private ColaboradorRepository colaboradorRepository;

    public ColaboradorController(ColaboradorRepository colaboradorRepository) {
        this.colaboradorRepository = colaboradorRepository;
    }


    @PostMapping("/colaborador")
    @Transactional
    public String create(@RequestBody ColaboradorForm colaboradorForm){
        Colaborador colaborador = colaboradorForm.converte();
        colaboradorRepository.save(colaborador);
        return colaborador.toString();
    }

    @GetMapping("/colaborador")
    public List<Colaborador> findAll(){
        return colaboradorRepository.findAll();
    }
}
```
**ColaboradorForm**
```
package com.example.demo;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Positive;

public class ColaboradorForm {

    @NotBlank
    private String nome;

    @NotBlank
    private TipoCargo cargo;

    @NotBlank
    @Positive
    private Double salario;

    public ColaboradorForm(String nome, TipoCargo cargo, Double salario) {
        this.nome = nome;
        this.cargo = cargo;
        this.salario = salario;
    }

    public Colaborador converte() {
        return new Colaborador(nome, cargo, salario);
    }
}
```

Podemos então cadastrar um colaborador via Postman e ver o funcionamento da nossa estratégia em utilizar o Enum.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u77qewd9vhrr5ft0hn9z.png)
Colaborador cadastrado com sucesso, e veja que passamos no corpo da requisição o salario de R$ 1000.00 mas o colaborador foi salvo no banco de dados com o salario no valor de R$1500.00
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ff19odk0mjviexc7nznm.png)
Isso porque o cargo do colaborador passado na requisição e referente ao enum no valor de AJUDANTE e este enum utiliza o método **bonificacaoColaborador** que acrescenta 50% a mais do valor do salario do colaborador.
Veja o que acontece se cadastrarmos este mesmo valor mas com o cargo de GERENTE.
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jdsk5qtt70s3409pdn37.png)
Teve um aumento de apenas 10% conforme especificamos no enum de valor GERENTE.
A vantagem de usarmos este tipo de abordagem e que se precisarmos acrescentar novos cargos e bonificações só será necessário acrescentar valores na classe Enum TipoCargo e implementar o método bonificacaoColaborador com a regra de negocio especifica daquele cargo.
Feito galera obrigado por ler ate aqui e ate a próxima, deixo meus contatos aqui para quem quiser me adicionar.

[linkedin](https://www.linkedin.com/in/nanialmeida/)
[github](https://github.com/2020nani)