DEV Community

Cover image for Enhanced Enums - Seus enums melhorados
Toshi Ossada for flutterbrasil

Posted on

Enhanced Enums - Seus enums melhorados

Enums é uma forma que posso trabalhar com valores predefinidos de forma constantes, uma vantagem disso é conseguirmos uma segurança em tempo de compilação, pois desta forma no momento que seu app estiver compilando, facilmente será identificado caso algum valor incorreto esteja sendo utilizado.

Vamos ao seguinte exemplo em que tenho uma classe Funcionario onde tem um método chamado imprimirRegimeContratacao que recebe uma String representando o tipo de contratação e me retorna uma descrição.

void main() {
final funcionario = Funcionario();
print(funcionario.imprimirRegimeContratacao('CLT'));
}
class Funcionario {
String imprimirRegimeContratacao(String tipoContratacao) {
if (tipoContratacao == 'CLT') {
return 'Contrato CLT';
} else if (tipoContratacao == 'PJ') {
return 'Contrato PJ';
} else if (tipoContratacao == 'Estagio') {
return 'Contrato ESTAGIARIO';
} else {
return 'Contrato não identificado';
}
}
}
view raw main.dart hosted with ❤ by GitHub

Isto me retornará o seguinte resultado.

Entretanto, se ao invés de passar “CLT” como parâmetro eu passar “clt”(em minúsculo) ocorrerá um problema.

void main() {
final funcionario = Funcionario();
print(funcionario.imprimirRegimeContratacao('clt'));
}
class Funcionario {
String imprimirRegimeContratacao(String tipoContratacao) {
if (tipoContratacao == 'CLT') {
return 'Contrato CLT';
} else if (tipoContratacao == 'PJ') {
return 'Contrato PJ';
} else if (tipoContratacao == 'Estagio') {
return 'Contrato ESTAGIARIO';
} else {
return 'Contrato não identificado';
}
}
}
view raw main.dart hosted with ❤ by GitHub

O problema do código acima é que ele está muito aberto para que ele aceite qualquer tipo de informação, este é um ótimo tipo de cenário para a utilização de ENUMERADORES, utilizando a palavra enum posso facilmente criar um enumerador.

void main() {
final funcionario = Funcionario();
print(funcionario.imprimirRegimeContratacao(TipoContratacao.clt));
}
enum TipoContratacao {
clt,
pj,
estagio,
}
class Funcionario {
String imprimirRegimeContratacao(TipoContratacao tipoContratacao) {
if (tipoContratacao == TipoContratacao.clt) {
return 'Contrato CLT';
} else if (tipoContratacao == TipoContratacao.pj) {
return 'Contrato PJ';
} else if (tipoContratacao == TipoContratacao.estagio) {
return 'Contrato ESTAGIARIO';
} else {
return 'Contrato não identificado';
}
}
}
view raw main.dart hosted with ❤ by GitHub

Desta forma eu não consigo mais passar um parâmetro inexistente, pois assim já estão predefinidos os valores que serão tratados.

Agora imagine que precisamos de um método que irá calcular o salário liquido do funcionário que irá receber o salário bruto e descontar o imposto de acordo com o tipo de contratação.

void main() {
final funcionario = Funcionario(TipoContratacao.clt);
print(funcionario.calcularPagamentLiquido(2000));
}
enum TipoContratacao {
clt,
pj,
estagio,
}
class Funcionario {
final TipoContratacao tipoContratacao;
Funcionario(this.tipoContratacao);
String imprimirRegimeContratacao() {
if (tipoContratacao == TipoContratacao.clt) {
return 'Contrato CLT';
} else if (tipoContratacao == TipoContratacao.pj) {
return 'Contrato PJ';
} else if (tipoContratacao == TipoContratacao.estagio) {
return 'Contrato ESTAGIARIO';
} else {
return 'Contrato não identificado';
}
}
calcularPagamentLiquido(double salarioBruto) {
return salarioBruto - (salarioBruto * valorImposto(tipoContratacao));
}
double valorImposto(TipoContratacao tipoContratacao) {
if (tipoContratacao == TipoContratacao.clt) {
return 0.2;
} else if (tipoContratacao == TipoContratacao.pj) {
return 0.1;
} else if (tipoContratacao == TipoContratacao.estagio) {
return 0.0;
} else {
return 0.0;
}
}
}
view raw main.dart hosted with ❤ by GitHub

No dart podemos colocar o método que retorna a porcentagem de imposto dentro do enum, desta forma toda vez que for utilizar deste enum já tenho predefinido a porcentagem que ele irá pagar, pois ele é um valor constante.

Antigamente (antes do Dart 2.17 e Flutter 3.0) precisamos fazer isto através de extensions e com isso conseguimos criar métodos dentro de nosso enum.

void main() {
final funcionario = Funcionario(TipoContratacao.pj);
print(funcionario.calcularPagamentLiquido(2000));
}
enum TipoContratacao {
clt,
pj,
estagio,
}
extension TipoContratacaoExt on TipoContratacao {
String get nome {
switch (this) {
case TipoContratacao.clt:
return 'Contrato CLT';
case TipoContratacao.pj:
return 'Contrato PJ';
case TipoContratacao.estagio:
return 'Contrato Estágio';
default:
return 'Não identificado';
}
}
double valorImposto(double salarioBruto) {
var imposto = 0.0;
switch (this) {
case TipoContratacao.clt:
imposto = 0.2;
break;
case TipoContratacao.pj:
imposto = 0.1;
break;
case TipoContratacao.estagio:
imposto = 0.0;
break;
default:
imposto = 0.0;
}
return salarioBruto * imposto;
}
}
class Funcionario {
final TipoContratacao tipoContratacao;
Funcionario(this.tipoContratacao);
String imprimirRegimeContratacao() {
return tipoContratacao.nome;
}
calcularPagamentLiquido(double salarioBruto) {
return salarioBruto - tipoContratacao.valorImposto(salarioBruto);
}
}
view raw main.dart hosted with ❤ by GitHub

No Flutter 3.0 tivemos o suporte ao Dart 2.17 que nos trouxe melhorias nos enumeradores possibilitando criarmos enums mais ricos com métodos e atributos, não necessitando criar extensions.

Desta forma podemos retirar a extension e passar todos os métodos para dentro do enum

void main() {
final funcionario = Funcionario(TipoContratacao.estagio);
print(funcionario.calcularPagamentLiquido(2000));
}
enum TipoContratacao {
clt,
pj,
estagio;
String get nome {
switch (this) {
case TipoContratacao.clt:
return 'Contrato ';
case TipoContratacao.pj:
return 'Contrato PJ';
case TipoContratacao.estagio:
return 'Contrato Estágio';
}
}
double valorImposto(double salarioBruto) {
var imposto = 0.0;
switch (this) {
case TipoContratacao.clt:
imposto = 0.2;
break;
case TipoContratacao.pj:
imposto = 0.1;
break;
case TipoContratacao.estagio:
imposto = 0.0;
break;
}
return salarioBruto * imposto;
}
final double imposto;
}
class Funcionario {
final TipoContratacao tipoContratacao;
Funcionario(this.tipoContratacao);
String imprimirRegimeContratacao() {
return tipoContratacao.nome;
}
calcularPagamentLiquido(double salarioBruto) {
return salarioBruto - tipoContratacao.valorImposto(salarioBruto);
}
}
view raw main.dart hosted with ❤ by GitHub

Agora também podemos criar propriedades dentro do enum para pré definir valores que serão constantes (ESTAS PROPRIEDADES DEVEM SER FINAL E IREMOS PASSAR NO CONSTRUTOR)

void main() {
final funcionario = Funcionario(TipoContratacao.clt);
print(funcionario.calcularPagamentLiquido(2000));
}
enum TipoContratacao {
clt(0.2),
pj(0.2),
estagio(0);
const TipoContratacao(this.imposto);
final double imposto;
String get nome {
switch (this) {
case TipoContratacao.clt:
return 'Contrato ';
case TipoContratacao.pj:
return 'Contrato PJ';
case TipoContratacao.estagio:
return 'Contrato Estágio';
}
}
double valorImposto(double salarioBruto) {
return salarioBruto * imposto;
}
}
class Funcionario {
final TipoContratacao tipoContratacao;
Funcionario(this.tipoContratacao);
String imprimirRegimeContratacao() {
return tipoContratacao.nome;
}
calcularPagamentLiquido(double salarioBruto) {
return salarioBruto - tipoContratacao.valorImposto(salarioBruto);
}
}
view raw main.dart hosted with ❤ by GitHub

Também posso trabalhar com contratos no enum, para predefinir métodos dos enums que irão implementá-los

void main() {
final funcionario = Funcionario(TipoContratacao.clt);
final funcionario2 = Funcionario(TipoContratacao.pj);
print(funcionario.igual(funcionario2));
print(funcionario.differenca(funcionario2));
}
abstract class Comparar<T> {
bool igual(T outro);
double differenca(T outro);
}
enum TipoContratacao implements Comparar<TipoContratacao> {
clt(0.2),
pj(0.1),
estagio(0);
const TipoContratacao(this.imposto);
final double imposto;
String get nome {
switch (this) {
case TipoContratacao.clt:
return 'Contrato ';
case TipoContratacao.pj:
return 'Contrato PJ';
case TipoContratacao.estagio:
return 'Contrato Estágio';
}
}
double valorImposto(double salarioBruto) {
return salarioBruto * imposto;
}
@override
bool igual(TipoContratacao outro) => outro.imposto == imposto;
@override
double differenca(TipoContratacao outro) => outro.imposto - imposto;
}
class Funcionario {
final TipoContratacao tipoContratacao;
Funcionario(this.tipoContratacao);
String imprimirRegimeContratacao() {
return tipoContratacao.nome;
}
calcularPagamentLiquido(double salarioBruto) {
return salarioBruto - tipoContratacao.valorImposto(salarioBruto);
}
bool igual(Funcionario outro) => tipoContratacao.igual(outro.tipoContratacao);
double differenca(Funcionario outro) =>
tipoContratacao.differenca(outro.tipoContratacao);
}
view raw main.dart hosted with ❤ by GitHub

Desta forma seus enumeradores ficam muito mais poderosos e muito mais legíveis, legal essa nova alteração né?

Tem vários exemplos em meu github entre, compartilhe e dê seu star em meu github :)

https://github.com/toshiossada

Image description

Entre em nosso discord para interagir com a comunidade: https://discord.com/invite/flutterbrasil
https://linktr.ee/flutterbrasil

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (0)

AWS Security LIVE!

Hosted by security experts, AWS Security LIVE! showcases AWS Partners tackling real-world security challenges. Join live and get your security questions answered.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️